Programmatic Provisioning#
Posit Connect supports the programmatic provisioning of an initial administrator user with an API key. This API key can then be used for scripted user provisioning and content deployment processes. This may be useful when, for example, Connect is deployed in an "immutable" environment where no content publication will take place once Connect is running, or for other automated deployment workflows.
Example Workflow#
The following section describes an example workflow that creates the first admin API key programmatically using the rsconnect-python
CLI.
Prerequisites#
- A fresh instance of Posit Connect with no pre-existing user accounts.
- The ability to generate a secret key for JSON Web Token (JWT) signing/verification.
- Access to the
rsconnect-python
CLI with Python version >= 3.6.
Limitations#
This workflow will fail if Connect is configured with password authentication without email sending. Password authentication without email sending relies on the initial administrator user to act as the account confirmation intermediary. This conflicts with the goal of the bootstrapped initial administrator, which is only intended to be an anchor for the first API key. The bootstrapped administrator account is not intended to have or provide UI access. This means that you will be unable to confirm any subsequent user accounts that are created on the Connect instance.
If this is problematic for your workflow, please reach out to your customer success representative to talk through possible options.
Generate a Secret Key#
Posit Connect currently supports HS256 as its signing/verification algorithm, with a required minimum secret length of 32 bytes.
You can create a valid keyfile with the following command:
Terminal
$ head -c 32 /dev/random | base64 > /path/to/secret.key
Save this secret key to a file.
Both rsconnect-python
and Posit Connect will need to be able to access this keyfile in the following steps.
This secret is a one-time key that holds no authority after this workflow is finished.
We recommend deleting it after provisioning is complete.
There are no strict requirements around the keyfile location on the filesystem.
You can verify the length of your secret key with the following commmand:
Terminal
$ cat /path/to/secret.key | base64 -d | wc -c
Warning
Currently, the only JWT signing algorithm supported is HMAC-SHA-256 (HS256), which is a symmetric-key algorithm. This means that the same secret needs to be shared between rsconnect-python
and Posit Connect. Asymmetric-key algorithms, which use public/private keypairs, are not currently supported.
This signing algorithm may not meet your needs if you do not have a secure way to share the generated secret between your client tool and Posit Connect.
Take care to ensure that you follow best practices around key generation and secret management.
Note
Posit Connect expects the secret key to be base64-encoded. If Connect is failing to load your secret correctly, verify that the secret is base64-encoded.
Configure Posit Connect#
Update your Posit Connect configuation to include the following:
/etc/rstudio-connect/rstudio-connect.gcfg
[Bootstrap]
Enabled = true
SecretKeyFile = /path/to/secret.key
This property allows Connect to read the secret from a file.
A secret key file may be the simplest approach if Connect and the client tool both have access to the same file system. For example, common access can be provided by a mounted file system in a cluster environment, or by running Connect and the client tool on the same host.
/etc/rstudio-connect/rstudio-connect.gcfg
[Bootstrap]
Enabled = true
SecretKey = <SECRET_KEY>
This property is designed to facilitate secret key injection with an environment variable.
Do not store the secret key itself in your configuration file.
Environment variables may aid simple and secure secret key transfer in certain environments. For example, you might use this property if you're running Connect in a Kubernetes cluster or similar environment where applications are commonly configured using environment variables.
This approach could also be useful if you control the "parent" system that is configuring your Connect environment. Environment variables may allow you to ephemerally inject the secret into your Connect environment without having to engage the filesystem.
The following example would inject the same configuration properties through environment variables:
Terminal
export CONNECT_BOOTSTRAP_ENABLED=true
export CONNECT_BOOTSTRAP_SECRETKEY=<SECRET_KEY>
This configuration change:
- Exposes the bootstrapping API endpoint which is used to provision the admin-scoped API key
- Provides Posit Connect with the secret key required to verify the JWT
If Posit Connect is currently running, restart the server.
Request an API key#
After installing rsconnect-python
, run the following command:
Terminal
$ rsconnect bootstrap --jwt-keypath </path/to/secret.key> --server <server_address>
If successful, rsconnect-python
will return an API key embedded in a JSON object:
{
"status": 200,
"api_key": <the_api_key>,
"message": "Success."
}
If an error occurs, this command will return a JSON object with a non-200 status, an empty string for api_key
, and an error message:
{
"status": <error_status>,
"api_key": "",
"message": <error_message>
}
Warning
The API Key will only be returned ONCE by Posit Connect. After the first successful response from the bootstrapping endpoint, subsequent requests will fail. If you lose access to the API key but have not successfully provisioned the Posit Connect instance, you will need to start over from the beginning with a fresh Connect instance.
If this command is embedded in a larger provisioning script, it may be useful to insert the API key directly into an environment variable. The rsconnect bootstrap
command provides an optional --raw
flag which extracts the API key from the surrounding json response before returning it. This allows a more complex script to do something like the following:
Terminal
$ export API_KEY=$(rsconnect bootstrap --raw --jwt-keypath </path/to/bootstrap.key> --server <server_address>)
Cleanup#
After provisioning, assuming that you have created a non-bootstrap administrator account with UI access, it is recommended that you:
- Disable the bootstrap admin account and revoke its API key.
- Disable the
Bootstrap
section of your Posit Connect config and restart Connect. - Delete the secret keyfile from your filesystem.
Troubleshooting#
Common rsconnect-python Errors#
Invalid secret key length#
Error: Secret key expected to be at least 32 bytes in length.
Your secret is too short. Use a secret key that is at least 32 bytes in length.
Because the secret is base64-encoded, you will not be able to review the key length in the secret file directly. You need to decode the key first.
To check the decoded secret length, you can use a command like:
Terminal
$ cat /path/to/secret.key | base64 --decode | wc -c
Common Error Responses#
401#
{
"status": 401,
"api_key": "",
"message": "JWT authorization failed."
}
rsconnect-python
and Connect. If you are constructing your JWT by hand, verify the payload contents and signature algorithm.
403#
{
"status": 403,
"api_key": "",
"message": "Unable to provision initial admin. Please check status of Connect database."
}
Warning
Remember that you can only successfully request the API key from the endpoint once.
404#
{
"status": 404,
"api_key": "",
"message": "Unable to find provisioning endpoint. Please check your 'rsconnect bootstrap --server' parameter and your Connect configuration."
}
Boostrap.Enabled
is set to true
in your config. Verify that the rsconnect bootstrap --server
parameter is correct.
FAQ#
What if I want to use a different client-side tool than rsconnect-python
?
rsconnect-python
can be replaced with custom clients, which will need to be able to produce a JWT and use it in a request against the Posit Connect API.
See the bootstrap endpoint documentation for more details on the Posit Connect API, and the "Custom Clients" section in the appendix for additional implementation details.
Who (or what) is the returned API key attached to? The API key is attached to an ephemeral administrator user. This admin user is not intended to provide access to the UI and can be disabled after provisioning is complete. If you provision another admin user and use it to log into the UI, you will see the bootstrapped admin in the list of registered users. It will have the username __bootstrap_admin__
.