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.