Vault is a tool for securely accessing secrets. A secret is anything that you want to tightly control access to, such as API keys, passwords, certificates, and more. Vault provides a unified interface to any secret while providing tight access control and recording a detailed audit log.
The CAS integration with vault has been available for some time. In this walkthrough, we are going to take a pass at getting CAS connected to Vault to store properties and settings. We will also try to reload settings dynamically in real-time as they are changed and updated inside Vault.
Our starting position is based on the following:
6.0.0-RC4
master
branch specifically)jq
To run Vault for development and testing, we can use the provided Docker image:
docker run --cap-add=IPC_LOCK -d -e 'VAULT_DEV_ROOT_TOKEN_ID=CAS' -p 8200:8200 --name=vault vault
docker ps
This runs a completely in-memory Vault server, which is useful for development but SHOULD NOT be used in production. Note the environment variable VAULT_DEV_ROOT_TOKEN_ID
which sets the ID of the initially generated root token to the given value. We will use this token, later on, to log into the Vault UI and it will be also be utilized when CAS attempts to connect to Vault.
To access the Vault UI, point your browser to http://localhost:8200/ui
and use the above token to log into Vault where you’d be greeted with the following screen:
So, let’s create a few secrets. Secrets inside Vault can be managed inside folders where from the CAS perspective, the folder hierarchy is expected to match the following:
/secret/{application}/{profile}
/secret/{application}
…where application
is the value of spring.application.name
which is by default cas
and the profile
is any a tag/label assigned to a collection of settings that would be activated and fetched if the CAS server is deployed using said profile(s). So, as an example, we can create a secret for cas.authn.accept.users
with the value of casuser::Vault
. We will put this secret inside the path /secret/cas/vault
where cas
is the name of our application and vault
is the profile name we shall activate when running CAS.
Note that I have added a number of other settings to allow access to the CAS actuator endpoints. This will allow us to refresh the state of CAS application context, once a setting is updated with a new value.
That should do for now. Let’s get CAS running.
Integration with Vault in CAS is handled using Spring Cloud Vault and can be done in a number of ways:
So in order to enable a CAS integration with Vault directly, you want to start with the CAS Overlay, clone the project and then put the following settings into a src/main/resources/bootstrap.properties
file:
spring.application.name=cas
spring.profiles.active=vault
spring.cloud.vault.host=localhost
spring.cloud.vault.port=8200
spring.cloud.vault.token=CAS
spring.cloud.vault.enabled=true
spring.cloud.vault.reactive.enabled=false
spring.cloud.vault.fail-fast=true
spring.cloud.vault.scheme=http
spring.cloud.vault.kv.enabled=true
spring.cloud.vault.kv.backend=secret
We are teaching CAS to find our Vault server at http://localhost:8200
and use the generated token CAS
for authenticated requests.
We have also enabled the versioned Key-Value secret backend. The key-value backend allows storage of arbitrary values as key-value store. A single context can store one or many key-value tuples. Contexts can be organized hierarchically. Per our previous work in Vault, the backend is called secret
.
Note that there are many other types of backends supported. See Spring Cloud Vault for more info.
Of course, don’t forget to include the required module in your CAS build:
compile "org.apereo.cas:cas-server-support-configuration-cloud-vault:${project.'cas.version'}"
Build and deploy. At this point, you should be able to log into CAS using casuser
and Vault
as the credentials!
If a secret changes, Vault has no way to broadcast the updated value(s) to its own clients, such as the CAS server itself. Therefore, in order to broadcast such change events CAS presents various endpoints that allow the user to refresh the configuration as needed. This means that an adopter would simply change a required CAS setting and then would submit a request to CAS to refresh its current state. At runtime! All CAS internal components that are affected by the external change are quietly reloaded and the setting takes immediate effect, completely removing the need for container restarts or CAS re-deployments.
For example, start by changing the value of cas.authn.accept.users
in Vault to something like casuser::HelloWorld
. Then, execute the following command to refresh the CAS application context:
curl -k -u casuser:Mellon https://sso.example.org/cas/actuator/refresh -d {} -H "Content-Type: application/json"
...
["cas.authn.accept.users"]
At this point, you should be able to log into CAS using casuser
and HelloWorld
as the credentials!
I hope this review was of some help to you and I am sure that both this post as well as the functionality it attempts to explain can be improved in any number of ways. Please feel free to engage and contribute as best as you can.
Monday-Friday
9am-6pm, Central European Time
7am-1pm, U.S. Eastern Time
Monday-Friday
9am-6pm, Central European Time