Advanced Client setup

Note

This page deals with advanced topics related to the RADKit Client. If you are just getting started, you may want to follow RADKit Client then move on to Introduction to RADKit Client, and come back to this section later.

Enrolling the Client

For some applications such as scripting and automation, it may be useful to authenticate the Client using a certificate instead of SSO. To enroll your Client, simply call the enroll_client() method on an SSO-authenticated Client object (see Starting RADKit Client on Windows/macOS), and when prompted, choose a secure password to protect the private key of your new Client identity certificate:

>>> client.enroll_client()
New private key password: *********
Confirm: *********

Danger

The private key and its passphrase are highly sensitive information. Their usage is strictly restricted to the owner of the keys, and those CANNOT BE SHARED UNDER ANY CIRCUMSTANCES. Sharing those credentials exposes the owner to impersonation attacks. Apply all possible security measures:

  • use a very strong passphrase;

  • never store the passphrase into code;

  • never store the passphrase into a code repository (e.g. Git);

  • use a vault whenever possible.

Sharing your private key or passphrase is akin to sharing your CCO credentials. Do not be careless. Keep your job. Keep your secrets safe.

You can then perform subsequent logins using certificate_login() instead of sso_login() still providing the email address associated with your Cisco account:

>>> certificate_login("myuserid@cisco.com")
Private key password: ***********

[CONNECTED] Client(status='CONNECTED')
-----------------  -----------------------------------------------------------
connected_domains  PROD (myuserid@cisco.com; certificate auth; authenticated )
services           not connected to any service
running_proxies    no local proxy running
-----------------  -----------------------------------------------------------
 HINT:  use grant_service_otp('<service_owner_email>') to authorize provisioning of a RADKit Service

Non-interactive authentication

Once the Client is enrolled, it is possible to pass the private key password in an environment variable so that the certificate_login() command will not interactively ask for the password.

This is done by setting the RADKIT_CLIENT_PRIVATE_KEY_PASSWORD_BASE64 environment variable with the password encoded in Base64, for example (on Linux or macOS):

% export RADKIT_CLIENT_PRIVATE_KEY_PASSWORD_BASE64="$( echo -n 'MyPassW0rd' | base64 )"
% radkit-client
>>> certificate_login("myuserid@cisco.com")
>>>

Danger

Storing a password in an environment variable is inherently insecure and is not recommended in any way, especially if the password unlocks credentials that grant access to a production environment. The Base64 encoding only protects against the most trivial over-the-shoulder password gleaning attacks. It does not provide any actual security. Use this authentication method at your own risk, preferably in a controlled and secure environment.

Controlling/Monitoring Automatic Certificate Renewal

The Client certificate is automatically renewed by the RADKit Client when it is about to expire. The renewal process is transparent to the user, and the Client will continue to operate normally without any intervention. This process is enabled by default, and can be disabled by setting cloud_client.automatic_certificate_renewal_enabled to false.

If certificate automatic renewal is disabled the owner of client is responsible for ensuring the certificate is renewed before it expires. Otherwise the client needs to be re-enrolled. When disabled, and the certificate is about to expire, the Client will emit a warning message indicating that the certificate is about to expire.

The process will start automatically 15 days before the certificate expires, this is the default value and can be adjusted by setting cloud_client.certificate_renewal_remaining_lifetime to the desired number of days. This same setting determines when the warning message is emitted if automatic certificate renewal is disabled.

The client authenticator provides attributes that allow the owner to track if the certificate renewal process ever took place and if so retrieve the EndpointCertificateBundlePaths object that points to the new certificate and private key.

Below is a code example that demonstrates how to monitor the certificate renewal process:

>>> certificate_login("myuserid@cisco.com")

.
.
.

11:34:45.816Z INFO  | Renewing certificate [serial='XXXXXXXXXX']
11:34:52.871Z INFO  | Saving new certificate [serial='YYYYYYYYY']
11:34:52.880Z INFO  | Certificate renewed and saved successfully. Revoking old certificate.
11:34:53.391Z INFO  | Old certificate revoked successfully.

>>> authenticator = client.authenticator
>>> authenticator.certificate_renewed
True

>>> authenticator.certificate_renewed_at
datetime(2024, 2, 28, 11, 31, 53, 757468)

>>> authenticator.new_certificate_path
EndpointCertificateBundlePaths(identity="myuserid@cisco.com", auth_hostname="prod.radkit-cloud.cisco.com", admin=False)

>>> authenticator.new_certificate_path.certificate_pem_path
PosixPath("/radkit/identities/prod.radkit-cloud.cisco.com/myuserid@cisco.com/certificate.pem")

>>> authenticator.new_certificate_path.chain_pem_path
PosixPath("/radkit/identities/prod.radkit-cloud.cisco.com/myuserid@cisco.com/chain.pem")

>>> authenticator.new_certificate_path.private_key_path
PosixPath("/radkit/identities/prod.radkit-cloud.cisco.com/myuserid@cisco.com/private_key_encrypted.pem")

Note

The certificate renewal process is only available when the client is certificate-authenticated.

Danger

Calling <client>.client.authenticator.certificate_renewed_at and/or <client>.client.authenticator.new_certificate_path will raise an exception if the certificate renewal process has not taken place. Always check the value of <client>.client.authenticator.certificate_renewed first to avoid exceptions, otherwise ensure your code handles the exception.

The state of the certificate renewal process can be cleared but calling <client>.client.authenticator.clear_certificate_renewal. This will set the certificate_renewed attribute to False and clear the certificate_renewed_at and new_certificate_path attributes.

>>> authenticator = client.authenticator
>>> authenticator.clear_certificate_renewal()
>>> authenticator.certificate_renewed
False

This is useful when a process is monitoring the certificate renewal process and wants to signal that its done and ready to monitor the next renewal process.