cki_tools.credentials

Access and manage CKI secrets

Manage credentials for service accounts and their meta data as stored in CKI secrets.

Life cycle of rotatable tokens

In general, tokens can be rotated via a three-step procedure by preparing a new token version, switching to it, and cleaning up afterwards.

Life cycle of service-side rotatable tokens

For services that support rotation directly, rotating a token normally means both creating a new token and invalidating the old one. As this would lead to downtime, two such tokens are created in advance, one of which is deployed and the other is prepared for deployment. The switch command then switches the deployed token to the prepared one.

step version 1 version 2 version 3
active deployed missing
MR 1: rotate the non-deployed version via prepare revoked deployed active
MR 2: switch to the new version via switch revoked active deployed

Life cycle tokens for services that do not support token rotation natively

For services that do not support token rotation natively, rotating a token is done by creating a new token version, switching over to it, and revoking the old token version.

step version 1 version 2
deployed missing
MR 1: create a new non-deployed version via prepare deployed active
MR 2: switch to the new version via switch active deployed
MR 3: revoke the old version via clean revoked deployed

Secrets

The secrets tool allows access to CKI variables and secrets.

$ python3 -m cki_tools.credentials.secrets --help
usage: secrets.py [-h] {secret,variable,edit,validate,login,logout} ...

Access CKI variables and secrets

positional arguments:
  {secret,variable,edit,validate,login,logout}
    secret              Retrieve a secret value
    variable            Retrieve a variable value
    edit                Edit a secret value
    validate            Validate stored secrets
    login               Log into secrets storage
    logout              Log out of secrets storage

  -h, --help            show this help message and exit
  --json                output in json format

The following CLI aliases are provided:

  • cki_secret == python3 -m cki_tools.credentials.secrets secret
  • cki_variable == python3 -m cki_tools.credentials.secrets variable
  • cki_edit_secret == python3 -m cki_tools.credentials.secrets edit
  • cki_secrets_validate == python3 -m cki_tools.credentials.secrets validate
  • cki_secrets_login == python3 -m cki_tools.credentials.secrets login
  • cki_secrets_logout == python3 -m cki_tools.credentials.secrets logout

CKI variables and secrets meta data are stored in YAML files. Encrypted secrets are stored in HashiCorp Vault.

Environment variables

Name Secret Required Description
CKI_SECRETS_FILE no yes Path to the secrets meta data file
CKI_VARS_FILE no yes Path to the variables file
VAULT_ADDR no yes Address of the Vault server expressed as a URL, including port
VAULT_MOUNT_POINT no no Mount point of the KV2 secrets engine
VAULT_APPROLE_SECRET_ID yes no Secret ID of the approle (service account)
VAULT_TOKEN yes no Vault client token, falls back to ~/.vault-token if not set

cki_secret

usage: secrets.py secret [-h] [--json] key

Retrieve a secret value

positional arguments:
  key         secret name

options:
  -h, --help  show this help message and exit
  --json      output in json format

For secrets, the file name for the secrets meta data needs to be specified in the CKI_SECRETS_FILE environment variable. The actual secrets are stored in HashiCorp Vault.

As an example, a secrets meta data file could look like:

foo:
  meta:
    token_type: aws_secret_access_key

Pointing CKI_SECRETS_FILE to it and calling cki_secret foo will try to retrieve the value of foo from HashiCorp Vault:

$ cki_secret foo
bar
$ cki_secret foo --json
"bar"

Conditions

Conditions allow to obtain a list of meta/data fields for multiple secrets via something like path[meta-key-1,!meta-key-2,...]. For all secrets that start with the given path, delimited by /, the given meta fields are obtained with a default of False. A secret is only included in the returned list if all conditions match, i.e. if they are True for a condition like meta-key-1, or False for a condition like !meta-key-2.

Supported locations

Location Description
some/path# dictionary of all key-value meta pairs
some/path#field value for the given meta field
some/path: dictionary of all key-value data pairs
some/path:field value for the given data field
some/path value for the value data field
some/path[cond1,cond2] list of the above for all matching secrets

cki_variable

usage: secrets.py variable [-h] [--json] key

Retrieve a variable value

positional arguments:
  key         variable name

options:
  -h, --help  show this help message and exit
  --json      output in json format

For variables, the file name needs to be specified in the CKI_VARS_FILE environment variable.

As an example, a variables file could look like:

foo: bar
baz: |
  some
  string  
qux:
  complex: value
bool: true
int: 15

Pointing CKI_VARS_FILE to it and calling cki_variable key will print the values of the various variables:

$ for i in foo baz qux bool int; do cki_variable $i; done
bar
some
string
{'complex': 'value'}
True
15

With --json, the output will be properly json-encoded:

$ for i in foo baz qux bool int; do cki_variable --json $i; done
"bar"
"some\nstring"
{"complex": "value"}
true
15

cki_edit_secret

usage: secrets.py edit [-h] key value

Edit a secret value

positional arguments:
  key         secret name
  value       new secret value

options:
  -h, --help  show this help message and exit

Secrets and their associated meta data can be edited as well. From the location syntax table above, all but the conditions are supported.

When editing meta data, the secrets meta data file is rewritten with the updated meta data. When editing secrets, the actual secret values are updated on HashiCorp Vault.

$ cat secrets.yml
foo:
  meta:
    token_type: aws_secret_access_key
$ cki_edit_secret foo#user_name aws-user-name
$ cat secrets.yml
foo:
  meta:
    token_type: aws_secret_access_key
    user_name: aws-user-name

cki_secrets_validate

usage: secrets.py validate [-h]

Validate stored secrets

options:
  -h, --help  show this help message and exit

Compare the list of secrets available in HashiCorp Vault and the secrets meta data. Exits with an exit code of 2 if secrets are missing in HashiCorp Vault. Exits with an exit code of 1 if secrets are only missing in the secrets meta data. Exits with an exit code of 0 if no difference is found.

cki_secrets_login

usage: secrets.py login [-h] [--duration DURATION] (--oidc | --approle APPROLE)

Log into secrets storage

options:
  -h, --help           show this help message and exit
  --duration DURATION  validity of the token
  --oidc               login via OIDC
  --approle APPROLE    login via given approle

Log into HashiCorp Vault either via OIDC (human user) or an approle (service account).

For OIDC, a Kerberos ticket is necessary to get past SSO.

For an approle, the approle secret ID needs to be provided in the VAULT_APPROLE_SECRET_ID environment variable.

If successful, the client token will be stored in ~/.vault-token as supported by the official vault CLI tooling.

cki_secrets_logout

usage: secrets.py logout [-h]

Log out of secrets storage

options:
  -h, --help  show this help message and exit

Log out of HashiCorp Vault by revoking the client token. Independent whether the API call is successful, the ~/.vault-token file will be removed.

Metrics

usage: python3 -m cki_tools.credentials.metrics [-h]

Print Prometheus metrics about secrets

options:
  -h, --help  show this help message and exit

This will output the following Prometheus metrics related to the stored credentials:

name labels description
cki_token_created_at name, active, deployed token creation timestamp
cki_token_expires_at name, active, deployed token expiration timestamp

Manager

usage: python3 -m cki_tools.credentials.manager
            [--token-name TOKEN_NAME]
            [--token-type-prefix TOKEN_TYPE_PREFIX]
            [--force]
            {create,destroy,rotate,update,validate,status,prepare,switch,clean}

Manage the lifecycle of secrets

positional arguments:
  {create,destroy,rotate,update,validate,status,prepare,switch,clean}
                        What to do

options:
  -h, --help            show this help message and exit
  --token-name TOKEN_NAME
                        Single token name
  --token-type-prefix TOKEN_TYPE_PREFIX
                        Filter by token type prefix
  --force               Force token rotation even if new enough

Low-level commands

command description
create create a new token as specified by the required meta data
destroy destroy an existing token, e.g. by revoking it
rotate create a new version of an existing token, which might invalidate the original version

Three-step rotation commands

command description
status show which tokens need rotation/preparation/cleanup
prepare prepare token versions for rotation
switch switch the deployed token version
clean clean token versions after rotation

Miscellaneous commands

command description
update update token meta data from the remote service
validate confirm with the remote services that active token versions are still valid
purge remove secrets and meta data for inactive token versions

Additionally, the validate commands check the following invariants about the versions of a token:

  • all versions have active, deployed and created_at fields
  • only one version is marked as deployed

GitLab project access tokens

  • Supported low-level commands: create, destroy, rotate
  • Supported features: three-step rotation, update, validate

See the API description for details.

name create description
(secret) updated secret token
token_type required gitlab_project_token
project_url required Project URL
scopes required Access scope
access_level required Access levels
token_name required Name of the token
token_id updated Project access token ID
created_at updated ISO8601 timestamp of creation
expires_at updated ISO8601 expiry date
revoked updated Whether the token is already revoked
active updated Whether the token is still active
user_id updated ID of associated user
user_name updated Name of associated user
deployed updated Whether the token is actually used

GitLab group access tokens

  • Supported low-level commands: create, destroy, rotate
  • Supported features: three-step rotation, update, validate

See the API description for details.

name create description
(secret) updated secret token
token_type required gitlab_group_token
group_url required Group URL
scopes required Access scope
access_level required Access levels
token_name required Name of the token
token_id updated Group access token ID
created_at updated ISO8601 timestamp of creation
expires_at updated ISO8601 expiry date
revoked updated Whether the token is already revoked
active updated Whether the token is still active
user_id updated ID of associated user
user_name updated Name of associated user
deployed updated Whether the token is actually used

GitLab personal access tokens

  • Supported low-level commands: destroy, rotate
  • Supported features: three-step rotation, update, validate

See the API description for details.

name rotate description
(secret) updated secret token
token_type required gitlab_personal_token
instance_url required GitLab instance URL
scopes updated Access scope
token_name updated Name of the token
token_id required Access token ID
created_at updated ISO8601 timestamp of creation
expires_at updated ISO8601 expiry date
revoked updated Whether the token is already revoked
active updated Whether the token is still active
user_id required ID of associated user
user_name updated Name of associated user
deployed updated Whether the token is actually used

GitLab project deploy tokens

  • Supported low-level commands: create, destroy
  • Supported features: three-step rotation, update, validate

See the API description for details.

name create description
(secret) updated secret token
token_type required gitlab_project_deploy_token
project_url required Project URL
scopes required Access scope
token_name required Name of the token
token_id updated Project deploy token ID
created_at updated ISO8601 timestamp of creation
expires_at optional ISO8601 expiry date
revoked updated Whether the token is already revoked
active updated Whether the token is still active
user_name updated Associated user name
deployed updated Whether the token is actually used

GitLab group deploy tokens

  • Supported low-level commands: create, destroy
  • Supported features: three-step rotation, update, validate

See the API description for details.

name create description
(secret) updated secret token
token_type required gitlab_group_deploy_token
group_url required Group URL
scopes required Access scope
token_name required Name of the token
token_id updated Group deploy token ID
created_at updated ISO8601 timestamp of creation
expires_at optional ISO8601 expiry date
revoked updated Whether the token is already revoked
active updated Whether the token is still active
user_name updated Associated user name
deployed updated Whether the token is actually used

GitLab runner authentication tokens

  • Supported features: update, validate

See the API description for details.

name update description
(secret) required secret token
token_type required gitlab_runner_authentication_token
instance_url required GitLab instance URL
token_id updated Group token ID
expires_at updated ISO8601 expiry date (optional)
active updated Whether the token is still active
deployed Whether the token is actually used

LDAP keytabs

  • Supported features: update
name update description
(secret) keytab, base64-encoded
token_type required ldap_keytab
ldap_server required LDAP server
dn required LDAP distinguished name
(LDAP attributes) updated LDAP object attributes

LDAP passwords

  • Supported features: update, validate
name update description
(secret) password
token_type required ldap_password
ldap_server required LDAP server
dn required LDAP distinguished name
(LDAP attributes) updated LDAP object attributes

AWS secret access keys

  • Supported low-level commands: create, destroy
  • Supported features: three-step rotation, update
name update description
(secret) secret access key
token_type required aws_secret_access_key
access_key_id required access key ID
endpoint_url required endpoint URL if not AWS
account updated AWS account number
user_name updated service account user name
arn updated service account user ARN
created_at updated ISO8601 timestamp of creation
active updated Whether the token is still active
deployed Whether the token is actually used

Dogtag certificates

  • Supported low-level commands: create
  • Supported features: three-step rotation, update, validate
name create description
(secret):private_key updated secret key
(secret):certificate updated certificate
token_type required dogtag_certificate
server_url required Dogtag server URL
serial_number updated Certificate serial number
issuer_dn updated Issuer DN
subject_dn required Subject DN
created_at updated ISO8601 timestamp of creation
expires_at updated ISO8601 timestamp of expiry
active updated Whether the certificate is still valid
deployed updated Whether the certificate is actually used

Splunk HEC tokens

  • Supported features: validate
name validate description
(secret) required HEC token
token_type required splunk_hec_token
endpoint_url required Splunk HEC endpoint base URL
index optional Splunk index

SSH keys

  • Supported low-level commands: create
  • Supported features: three-step rotation, update, validate
name create description
(secret):private_key updated secret key
(secret):public_key updated certificate
token_type required ssh_private_key
comment required Public key comment (name)
key_size required RSA key size
created_at updated ISO8601 timestamp of creation
active updated Whether the key is still valid
deployed updated Whether the key is actually used

Generic passwords

  • Supported low-level commands: create
  • Supported features: three-step rotation

Passwords are created via diceware.

name create description
(secret) updated password
token_type required password
created_at updated ISO8601 timestamp of creation
active updated Whether the key is still valid
deployed updated Whether the key is actually used

HashiCorp Vault secret IDs

  • Supported low-level commands: create, destroy
  • Supported features: three-step rotation, validate

Only HashiCorp Vault AppRole auth secret IDs are supported.

name create description
(secret) updated secret ID
token_type required hv_approle_secret_id
vault_addr required HashiCorp Vault URL
role_id required role name
secret_id_accessor updated secret ID accessor
created_at updated ISO8601 timestamp of creation
active updated whether the secret ID is still valid
deployed updated whether the secret ID is actually used

Configuration via environment variables

Name Secret Required Description
GITLAB_TOKENS no yes URL/environment variable pairs of GitLab instances and private tokens
GITLAB_TOKEN yes yes GitLab private tokens as configured in GITLAB_TOKENS above
CKI_LOGGING_LEVEL no no logging level for CKI modules, defaults to WARN; to get meaningful output on the command line, set to INFO