Cloud credentials in OpenShift-on-OpenStack are stored in a secret in the kube-system namespace.

Rotating credentials entails:

  1. Create the new credentials in OpenStack
  2. Build a clouds.yaml with the new credentials
  3. Upload the new clouds.yaml to the Kubernetes secret
  4. Let the operators distribute the new secret.

When using application credentials, this translates to:

# Step 0: Get the current credentials for the cluster. Useful later to replace values

# Step 1: Create the new credentials in OpenStack
openstack application credentials create new-creds-1

# Step 2: Build a `clouds.yaml` with the new credentials.
# Get the current credentials from OCP, and replace with the new values from Step 2.
# Save as `c.yaml` for example.
oc -n kube-system get secret openstack-credentials -o jsonpath='{.data.clouds\.yaml}' | base64 -d

# Step 3: Upload the new `clouds.yaml` to the `openstack-credentials` secret
oc set data -n kube-system secret/openstack-credentials clouds.yaml="$(<"c.yaml")"

# Step 4: Enjoy.

Automate clouds.yaml generation

First, build a script that creates new application credentials and directly outputs a clouds.yaml based on a template. We asssume that the cloud in question is openstack, which is what you’ll find in the OpenShift secret.

The script takes two arguments: an arbitrary name for the OpenStack credential, and one existing clouds.yaml.

openstack-appcreds() {
	declare \
		name="${1:?Missing positional argument: the name of the new application credential}" \
		template="${2:?Missing positional argument: the template where to replace the auth values}"
	shift; shift

	if [[ ! -r "$template" ]]; then
		echo 'The template must be a readable file'
		return
	fi

	yq --yaml-output --slurpfile appcreds <(openstack application credential create -f json "$name" "$@") '.
		| del(.clouds.openstack.auth.username)
		| del(.clouds.openstack.auth.password)
		| del(.clouds.openstack.auth.user_domain_name)
		| del(.clouds.openstack.auth.project_id)
		| del(.clouds.openstack.auth.project_name)
		| del(.clouds.openstack.auth.project_domain_name)
		| .clouds.openstack.auth_type="v3applicationcredential"
		| .clouds.openstack.auth.application_credential_id=$appcreds[0].id
		| .clouds.openstack.auth.application_credential_secret=$appcreds[0].secret
		' <(yq '.' "$template")
}

Example:

openstack-appcreds tmp-1 c.yaml

The script passes any further argument to the OpenStack command. Example with expiring credentials:

openstack-appcreds tmp-1 c.yaml --expiration "$(date -d '+1 hour' +%Y-%m-%dT%H:%M:%S --utc)"

This script can take a password-based clouds.yaml as a template.

Rotate credentials in a single step

By leveraging the script above, the whole process can be compressed in one single command:

oc set data -n kube-system secret/openstack-credentials clouds.yaml="$(
	openstack-appcreds 'tmp-1' <(
		oc -n kube-system get secret openstack-credentials -o jsonpath='{.data.clouds\.yaml}' | base64 -d
	)
)"