Certificate Authentication
This feature requires an Anka Enterprise (or higher) license.
- With the combined (controller + registry) native macOS package: You’ll edit the
/usr/local/bin/anka-controllerd
, enable TLS/HTTPS (required), and then enable certificate authentication. - With the docker package: You’ll edit the
docker-compose.yml
, enable TLS/HTTPS, and then enable certificate authentication. - With either the controller or registry standalone packages: You’ll edit the proper config files, enable TLS/HTTPS, and then enable certification authentication.
Requirements
- A Root CA certificate. For more information about CAs, see https://en.wikipedia.org/wiki/Certificate_authority. Usually provided by your organization or where you obtain your certificate signing. We will generate a self-signed one in this guide and refer to this as anka-ca-crt.pem and anka-ca-key.pem.
- Certificate[s] (signed with the Root CA) for the Anka Build Cloud Controller & Registry.
- Certificate[s] (signed with the Root CA) for your Anka Build Nodes so they can connect/authenticate with the Anka Build Cloud Controller & Registry.
If bringing your own certs, make sure they are not password protected (“encrypted”) (use openssl rsa -in <encrypted_private.key> -out <decrypted_private.key>
to decrypt).
1. Create a self-signed Root CA certificate
If you don’t have a Root CA yet, you can create it with openssl:
cd ~
openssl req -new -nodes -x509 -days 365 -keyout anka-ca-key.pem -out anka-ca-crt.pem \
-subj "/O=MyGroup/OU=MyOrgUnit/CN=MyUser"
You can add the Root CA to the System keychain so the Root CA is trusted and you can avoid warnings when you go to access the Controller UI.
sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain anka-ca-crt.pem
2. Configuring TLS for Controller & Registry
- TLS/HTTPS is required for Certificate Authentication.
- Your HTTPS/TLS cert can be from any root CA and does not need to be from the same CA as your authentication certs.
Create a self-signed cert for the services (optional)
Certificates should be in PEM (PKCS #8)
format.
Ensure your certs are decrypted! They cannot have passwords.
For this guide, we’re running the Controller & Registry locally, so we use 127.0.0.1. Update this depending on where you have things hosted
If you do not have TLS certificates for your Controller & Registry from a signed source, you can create them using your own CA:
export CONTROLLER_ADDRESS="127.0.0.1"
export REGISTRY_ADDRESS=$CONTROLLER_ADDRESS
openssl genrsa -out anka-controller-key.pem 4096
openssl req -new -nodes -sha256 -key anka-controller-key.pem -out anka-controller-csr.pem -subj "/O=MyGroup/OU=MyOrgUnit/CN=MyUser" \
-reqexts SAN -extensions SAN \
-config <(cat /etc/ssl/openssl.cnf <(printf "[SAN]\nextendedKeyUsage = serverAuth\nsubjectAltName=IP:$CONTROLLER_ADDRESS"))
openssl x509 -req -days 365 -sha256 -in anka-controller-csr.pem -CA anka-ca-crt.pem -CAkey anka-ca-key.pem -CAcreateserial \
-out anka-controller-crt.pem -extfile <(echo subjectAltName = IP:$CONTROLLER_ADDRESS)
You can use the same certificate for both the Controller and Registry.
Beginning in Controller version 1.12.0, you can control the allowed TLS Cipher Suites and minimum/maximum TLS versions.
Next, ensure that the certificate has Signature Algorithm: sha256WithRSAEncryption using openssl x509 -text -noout -in ~/anka-controller-crt.pem | grep Signature
(https://support.apple.com/en-us/HT210176)
Configure the services to use the TLS cert
MacOS combined Controller & Registry package
Edit /usr/local/bin/anka-controllerd
:
- Change the listen address to
443
:export ANKA_LISTEN_ADDR=":443"
SSL will actually work on any port you want.
Add the following ENVs to enable HTTPS:
# SSL + Cert Auth export ANKA_USE_HTTPS="true" export ANKA_SERVER_CERT="/Users/MyUser/anka-controller-crt.pem" export ANKA_SERVER_KEY="/Users/MyUser/anka-controller-key.pem"
Ensure
https
is in the registry URL:export ANKA_ANKA_REGISTRY="https://anka.registry:8089"
The Controller & Registry runs as root. This is why you need to specify the absolute path to the location where you generated or are storing your certs.
Linux/Docker Controller & Registry package
Within the docker-compose.yml
:
- Change the anka-controller ports from
80:80
to443:80
. You can keep the anka-registry ports the same (default: 8089). - Under the anka-controller, modify or set ANKA_ANKA_REGISTRY to use
https://
. - Ensure there is a
volumes
item that points the local cert location inside of the container at/mnt/cert
.
Now let’s configure the Controller & Registry containers/services to use those certificates:
version: '2'
services:
anka-controller:
container_name: anka-controller
build:
context: controller
ports:
- "443:80"
depends_on:
- etcd
- anka-registry
restart: always
volumes:
- "/opt/secure/certs:/mnt/certs"
environment:
ANKA_ANKA_REGISTRY: "https://anka.registry:8089"
ANKA_USE_HTTPS: "true"
ANKA_SKIP_TLS_VERIFICATION: "true" # Only needed if registry cert is self-signed
ANKA_SERVER_CERT: "/mnt/certs/anka-controller-crt.pem"
ANKA_SERVER_KEY: "/mnt/certs/anka-controller-key.pem"
anka-registry:
container_name: anka-registry
build:
context: registry
ports:
- "8089:8089"
restart: always
volumes:
- "/opt/anka-storage:/mnt/vol"
- "/opt/secure/certs:/mnt/certs"
environment:
ANKA_USE_HTTPS: "true"
ANKA_SERVER_CERT: "/mnt/certs/anka-controller-crt.pem"
ANKA_SERVER_KEY: "/mnt/certs/anka-controller-key.pem"
For the standalone package (separate docker containers for the controller and registry): If the SERVER_CERT and KEY is self-signed, you will need to setANKA_SKIP_TLS_VERIFICATION
totrue
in the controller config so it can connect to the registry.
Test the Configuration
Start or restart your Controller and/or Registry and test the new TLS configuration using https://
. You can also try using curl -v https://$CONTROLLER_OR_REGISTRY_URL/api/v1/status
.
If that doesn’t work, try to repeat the above steps and validate that the file names and paths are correct. If you are still having trouble, debug the system as explained in the Debugging Controller section.
3. Creating self-signed Node Certificates
The Controller’s authentication module uses the Root CA (anka-ca-crt.pem) to authenticate any incoming requests. When the Node sends the requests to the Controller, it will present its certificates. Those certificates must have been generated from the Root CA and also, if using Enterprise Plus, have the necessary permissions.
You can use the following openssl commands to create Node certificates using the Root CA:
NODE_NAME="$(hostname)"
ORG_UNIT="TEAM_ONE"
ORGANIZATION="MYORG"
openssl genrsa -out node-$NODE_NAME-key.pem 4096
openssl req -new -sha256 -key node-$NODE_NAME-key.pem -out node-$NODE_NAME-csr.pem \
-subj "/O=$ORGANIZATION/OU=$ORG_UNIT/CN=$NODE_NAME"
openssl x509 -req -days 365 -sha256 -in node-$NODE_NAME-csr.pem -CA anka-ca-crt.pem -CAkey anka-ca-key.pem \
-CAcreateserial -out node-$NODE_NAME-crt.pem
4. Configuring the Controller & Registry to enable authentication
In addition to the node certificates, the controller itself makes API calls to the Registry (you’ve enabled registry auth, right?) to get templates, etc, and will need a client cert to communicate with it. This is where ANKA_CA_CERT
comes in as it’s used to validate the incoming requests.
NAME="anka-controller"
ORG_UNIT="TEAM_ONE"
ORGANIZATION="MYORG"
openssl genrsa -out $NAME-key.pem 4096
openssl req -new -sha256 -key $NAME-key.pem -out $NAME-csr.pem \
-subj "/O=$ORGANIZATION/OU=$ORG_UNIT/CN=$NODE_NAME"
openssl x509 -req -days 365 -sha256 -in $NAME-csr.pem -CA anka-ca-crt.pem -CAkey anka-ca-key.pem \
-CAcreateserial -out $NAME-crt.pem
MacOS combined Controller & Registry package
Edit the /usr/local/bin/anka-controllerd
and ensure the following ENVs exist:
export ANKA_ENABLE_AUTH="true"
export ANKA_CA_CERT="/Users/MyUser/anka-ca-crt.pem"
export ANKA_CLIENT_CERT="/Users/MyUser/anka-controller-crt.pem"
export ANKA_CLIENT_CERT_KEY="/Users/MyUser/anka-controller-key.pem"
Linux/Docker Controller & Registry package
Within the docker-compose.yml
, add the following ENVs:
version: '2'
services:
anka-controller:
container_name: anka-controller
. . .
environment:
. . .
ANKA_ENABLE_AUTH: "true"
ANKA_CA_CERT: "/mnt/certs/anka-ca-crt.pem"
ANKA_CLIENT_CERT: "/mnt/certs/anka-controller-crt.pem"
ANKA_CLIENT_CERT_KEY: "/mnt/certs/anka-controller-key.pem"
anka-registry:
container_name: anka-registry
. . .
environment:
. . .
ANKA_ENABLE_AUTH: "true"
ANKA_CA_CERT: "/mnt/certs/anka-ca-crt.pem"
TheANKA_CA_CERT
is the authority that is used to validate the Anka Node Agent (ankacluster join
) certs.
Until you have an Enterprise licensed Node joined to the Controller, it won’t enable authentication for the Controller.
If you’re connecting the Anka CLI with the HTTPS Registry URL, you can use the Node certificates:anka registry --cert /Users/$USER_WHERE_CERTS_ARE/node-$NODE_NAME-crt.pem --key /Users/$USER_WHERE_CERTS_ARE/node-$NODE_NAME-key.pem add $REGISTRY_NAME https://$REGISTRY_ADDRESS:8089
(--cacert
may also be needed if you’re using a self-signed HTTPS cert and it’s not in your keychain)
Joining and Testing your Node and Controller Auth
First, copy both the Node certificates (node-$NODE_NAME-crt.pem
, node-$NODE_NAME-key.pem
) and the anka-ca-crt.pem
to the host/node you wish to join.
If you previously joined your Nodes to the Controller, you’ll want tosudo ankacluster disjoin
on each before proceeding (if it hangs, useps aux | grep anka_agent | awk '{print $2}' | xargs kill -9
and try disjoin again).
Note: Certificates are cached, so if you update/renew them, you need to either:
- disjoin and re-join them to the controller, issue
sudo pkill -9 anka_agent
on each node to restart the agent- or, issue a
<controller>/v1/node/update
PUT to the controller API to forcefully update all nodes.
If you’re using a signed certificate for the controller dashboard, but self-signed certificates for your nodes and CI tools, you’ll need to specify the--cacert
forankacluster join
andanka registry add
commands and point it to the signed CA certificate. You’ll usually seeSSLError: ("bad handshake: Error([('SSL routines', 'tls_process_server_certificate', 'certificate verify failed')],)",)
if the wrong CA is being used.
Then, use the ankacluster
command to connect it to the Controller with:
sudo ankacluster join https://$CONTROLLER_ADDRESS --skip-tls-verification \
--cert /Users/$USER_WHERE_CERTS_ARE/node-$NODE_NAME-crt.pem --cert-key /Users/$USER_WHERE_CERTS_ARE/node-$NODE_NAME-key.pem --cacert /Users/nathanpierce/anka-ca-crt.pem
Testing connection to Controller...: OK
Testing connection to registry….: OK
Ok
Cluster join success
The--skip-tls-verification
is only necessary if using a self-signed cert. Please avoid using--skip-tls-verification
AND the--cacert
.
Testing
Restart your Controller & Registry and then test the status endpoint with curl:
curl --insecure -v https://$HOST/api/v1/status
The response you should get is a 401 Authentication Required similar to below:
> GET /api/v1/status HTTP/2
> Host: localhost:80
> User-Agent: curl/7.58.0
> Accept: */*
>
* Connection state changed (MAX_CONCURRENT_STREAMS updated)!
< HTTP/2 401
< content-type: application/json
< content-length: 54
< date: Thu, 28 Nov 2019 16:58:23 GMT
<
{"status":"FAIL","message":"Authentication Required"}
If this is the response you get, it means the authentication module is working.
Let’s try to get a response using the Node certificate we created. Execute the same command, but now pass Node certificate and key:
curl --insecure -v https://$CONTROLLER_ADDRESS/api/v1/status --cert /Users/$USER_WHERE_CERTS_ARE/node-$NODE_NAME-crt.pem --key /Users/$USER_WHERE_CERTS_ARE/node-$NODE_NAME-key.pem
If everything is configured correctly, you should see something like this (I used 127.0.0.1 to setup this example):
* Trying 127.0.0.1...
. . .
> GET /api/v1/status HTTP/2
> Host: 127.0.0.1:80
> User-Agent: curl/7.64.1
> Accept: */*
>
* Connection state changed (MAX_CONCURRENT_STREAMS == 250)!
< HTTP/2 200
< cache-control: no-store
< content-type: application/json
< content-length: 184
< date: Sun, 12 Apr 2020 04:26:13 GMT
<
{"status":"OK","message":"","body":{"status":"Running","version":"1.7.0-4e6617d3","registry_address":"https://127.0.0.1:8089","registry_status":"Running","license":"enterprise plus"}}
* Connection #0 to host 127.0.0.1 left intact
* Closing connection 0
6. Configuring your Builder Node to push to the Registry
Typically you want to assign a specific Anka Node as a “builder node”. This node will run a licensed Anka installation and allow you to create and prepare VMs to be pushed to the Anka Build Cloud Registry as templates/tags. With Certificate Authentication enabled, you won’t be able to do this unless you specify the certs on the anka registry
command:
> anka registry --help
usage: registry [options] <command>
Configure and control template registries
options:
-r,--remote <val> Sets an alternate registry
--insecure Skip TLS verification
--cert <val> Path to a client certificate (if user authentication is configured)
--key <val> Path to private key if the client certificate doesn't contain one
--cacert <val> Use custom CA certificates location (default is /etc/ssl/certs)
--api-key-id <val> TAP identity
--api-key <val> TAP key in PEM form
commands:
list-repos List registries configured
add Add a registry
set Set default registry
remove Remove a registry from the configuration
list List templates in registry (see anka-push/pull commands)
show Show a template's properties
revert Delete a template or tag
You can also use anka registry add
to add it to the default configuration and not need to pass these in as options each execution:
> anka registry add --help
usage: add [options] name url
Add a registry
arguments:
name Registry name
url Registry URL
options:
-f,--force Do not perform a connectivity checks for the url
Accessing the Controller UI
Once Cert Auth as been enabled, loading your Controller UI will show Controller Not Connected
. This is because the Controller is fully protected. In order to access the UI, you can set up your browser to use client certificates to access the page. Alternatively, you can enable root token auth with ANKA_ROOT_TOKEN
which must be set to a minimum of 10 characters. You can read more about it here.
Certificate Revocation
Starting in 1.32.0, users can now revoke certificates without needing to change the CA or permissions.
Generating the Certificate Revocation List
- Locally on your machine you’ll create
openssl.cnf
(anywhere on your machine), containing various definitions:
[ ca ]
default_ca = CA_default # The name of the CA configuration to be used.
# can be anything that makes sense to you.
[ CA_default ]
dir = . # Directory where everything is kept
certs = $dir # Directory where the issued certs are kept
crl_dir = $dir # Directory where the issued crl are kept
database = $dir/index.txt # database index file.
#unique_subject = no # Set to 'no' to allow creation of
# several certificates with same subject.
new_certs_dir = $dir # Default directory for new certs.
certificate = $dir/anka-ca-crt.pem # The CA certificate
serial = $dir/serial # The current serial number
crlnumber = $dir/crlnumber # The current crl number
# must be commented out to leave a V1 CRL
crl = $dir/crl.pem # The current CRL
private_key = $dir/anka-ca-key.pem # The private key
RANDFILE = $dir/.rand # private random number file
x509_extensions = usr_cert # The extentions to add to the cert
name_opt = ca_default # Subject Name options
cert_opt = ca_default # Certificate field options
default_days = 365 # how long to certify for
default_crl_days= 30 # how long before next CRL
default_md = sha1 # use public key default MD
preserve = no # keep passed DN ordering
policy = policy_match
- Next, create
index.txt
andcrlnumber
and store them in a centralized location:
Any revocations must happen against the latestindex.txt
andcrlnumber
(openssl.cnf
is optional). It’s best to store these in a repo or somewhere that admins revoking can pull the latest versions and then commit them once complete.
touch index.txt # stores revoked certificates database
echo "01" > crlnumber # needs to be only initialized once
- Generate your first Certificate Revocation List (a.k.a “CRL”):
openssl ca -gencrl \
-config openssl.cnf \
-keyfile anka-ca-key.pem \
-cert anka-ca-crt.pem \
-out crl.pem \
-crldays 365
- If Certificate Authentication is enabled for both the Controller and Registry, you’ll need to set
ANKA_CRL
in both configs to the Revocation List File (.pem). If using Docker, you’ll need to attach a mount/volume that contains this file and target the destination/location inside of the container. - Generate your client certificates with
openssl
as you normally would, using the same root CA you used to generate the CRL.
Revoking a certificate
- When you need to revoke a certificate, you can use the following to add the cert to the
index.txt
database file:
openssl ca -config openssl.cnf \
-revoke node-Veertu.local-crt.pem \
-keyfile anka-ca-key.pem \
-cert anka-ca-crt.pem
- Once revoked, you must re-generate the CRL file and update it on the Controller and Registry, restarting them once updated:
openssl ca -gencrl \
-config openssl.cnf \
-keyfile anka-ca-key.pem \
-cert anka-ca-crt.pem \
-out crl.pem \
-crldays 365
Some things to note
- You can check if a certificate is revoked with
openssl verify -crl_check -CAfile anka-ca-crt.pem -CRLfile crl.pem node-Veertu.local-crt.pem
. - The
index.txt
,crlnumber
, and certs generated should be stored in a centralized location. We recommend a repo or a server with openssl on it that only admins have access to. Any changes made should be checked into the repo so that others can pull them and start from the latest version of the revocation DB (index.txt). - If the
crl.pem
expires, the controller and registry will fail. - The
crl.pem
must be generated with CA Root cert that the Controller and Registry are using.
Managing User/Group Permissions (Authorization)
Certificate Authentication users:
When creating certificates, you’ll want to specify CSR values using openssl’s
-subj
option. For example, if we’re going to generate a certificate so our Jenkins instance can access the Controller & Registry, you’ll want to use something like this:-subj "/O=MyOrgName/OU=$ORG_UNIT/CN=Jenkins"
- At least one
O=
andCN=
is required.- You can specify multiple
O=
like so:/O=DevOps/O=iOSDEV/ . . .
- Within the Controller’s Permission administration panel, we use
O=
as the Group Name andCN=
as the Username.- Spaces are supported in
O=
and Anka Build Cloud Controller version >= 1.10.
By default, ANKA_ENABLE_AUTH
will not use authorization/permissions and allow any certs or users to connect to all API endpoints and pages in the UI. In order to enable Authorization, you will need to include specific ENVs in your config:
ANKA_ENABLE_CONTROLLER_AUTHORIZATION
works for both combined and standalone (docker) packages.ANKA_ENABLE_REGISTRY_AUTHORIZATION
is for the combined (controller + registry in one binary) package only.ANKA_ENABLE_AUTHORIZATION
is only for the standalone registry package.
Permission groups are configurable from your Controller’s https://<controller address>/admin/ui
page. You can target and add permissions for either the group name or the username (which is different between the various Advanced Security Features we offer).
This feature requires Enterprise Plus. The regular enterprise license automatically adds all permissions to each certificate or token that is used and gives no control over them.
This also requires that you’ve enabled Root Token Authentication, giving you super user access to the controller UI and permissions.
The permission groups here differ from the groups you assign to nodes within the Controller UI.
The Available Permissions list will display all of the permissions we can assign to the group (see below for the full list). These permissions will allow plugins/users (like Jenkins) to communicate with the Controller & Registry:
Minimum Recommended Permissions
get_groups
get_registry_disk_info
list_images
list_nodes
list_vms
save_image
start_vm
terminate_vm
update_vm
view_logs
Controller Permissions
Permission | Description |
---|---|
Instances | |
list_vms | gives the user permission to list vms |
start_vm | gives the user permission to start vm |
terminate_vm | gives the user permission to terminate vm |
Registry | |
get_registry_files | gives the user permission to get registry files (logs) |
view_logs | gives the user permission to view log files in dashboard |
get_registry_disk_info | gives the user permission to get registry disk info |
registry_list | gives the user permission to list vms on registry |
registry_delete | gives the user permission to registry delete |
Nodes | |
list_nodes | gives the user permission to list nodes |
delete_node | gives the user permission to delete node |
change_node_config | gives the user permission to change node configuration |
Node Groups | |
create_group | gives the user permission to create node groups |
get_groups | gives the user permission to view node groups |
delete_group | gives the user permission to delete node groups |
update_group | gives the user permission to update node groups |
add_node_to_group | gives the user permission to add a node to a node group |
remove_group_from_node | gives the user permission to remove a node from node group |
Distribute VMs | |
registry_distribute | gives the user permission to distribute vms from registry |
registry_distribute_status | gives the user permission to view distribution statuses |
Config | |
change_config | gives the user permission to change global configuration |
get_config | gives the user permission to view global configuration |
Permissions and groups | |
view_permissions | gives the user permission to view the list of available permissions |
view_prmission_groups | gives the user permission to view permission groups |
update_permission_groups | gives the user permission to update permission groups |
delete_permission_groups | gives the user permission to delete permission groups |
Registry Permissions
Permission | Description |
---|---|
Information about Registry | |
index | gives the user permission to view the registry index (welcome html file) |
get_disk_info | gives the user permission to get disk info |
List VMs | |
list_vms | gives the user permission to list vms |
Push VMs | |
head_push_vm | gives the user permission to “negotiate” a push (understand which files exists on the server and which files need to be sent) |
push_vm | gives the user permission to push vm and create new vms or tags |
Pull VMs | |
pull_vm | gives the user permission to get a pull vm request (list of files needed for download and their paths) |
download_vm | gives the user permission to download vm files (as given by pull_vm) |
Delete VMs | |
delete_vm | gives the user permission to delete a vm |
revert | gives the user permission to revert vm versions |
File Server | |
upload_file | gives the user permission to upload a file |
download_file | gives the user permission to download a file |
Log Server | |
get_streamer | gives the user permission to get an html streamer page (for logs) |
stream_log | gives the user permission to stream a log file (as given by get_streamer) |
get_log_archive | gives the user permission to download a log archive (tar.gz) |
send_log_event | gives the user permission to send log events (only applies specifically to eventLog) |
send_log | gives the user permission to send a log file row |
Permissions and groups | |
view_permissions | gives the user permission to view the list of available permissions |
view_prmission_groups | gives the user permission to view permission groups |
update_permission_groups | gives the user permission to update permission groups |
delete_permission_groups | gives the user permission to delete permission groups |
6. Final Notes
- If you enabled AUTH for the registry, you’ll need to ensure that you set the
ANKA_CLIENT_CERT
andANKA_CLIENT_CERT_KEY
in your controller config or else it won’t be able to communicate with the registry.ANKA_CLIENT_CERT (string) (Certificate Authentication) The Controller will use this when making http requests, mainly to the Registry ANKA_CLIENT_CERT_KEY (string) (Certificate Authentication) The Controller will use this when making http requests, mainly to the Registry
- You may notice that the Controller UI doesn’t load or acts strangely. You will need to enable Root Token Authentication to access the controller UI.
- If you get an invalid cert error from the Controller UI, make sure that you add the root CA you generated to your system keychain.