Pantheon’s Secrets Manager Terminus plugin is key to maintaining industry best practices for secure builds and application implementation. Secrets Manager provides a convenient mechanism for you to manage your secrets and API keys directly on the Pantheon platform.
- Overview
- Concepts
- The life of a secret
- Plugin Usage
- Rate Limiting
- Use Secrets with Integrated Composer
- Use Secrets in Drupal through the Key module
-
Securely host and maintain secrets on Pantheon
-
Create and update secrets via Terminus
-
Use private repositories in Integrated Composer builds
-
Ability to set a
COMPOSER_AUTH
environment variable and/or a Composerauth.json
authentication file with Terminus commands -
Ability to define site and org ownership of secrets
-
Propagate organization-owned secrets to all the sites in the org
-
Ability to define the degree of secrecy for each managed item
-
Secrets are encrypted at rest
The Secrets Manager plugin is available for Early Access participants. Features for Secrets Manager are in active development. Pantheon's development team is rolling out new functionality often while this product is in Early Access. Visit the Pantheon Slack channel (or sign up for the channel if you don't already have an account) to learn how you can enroll in our Early Access program. Please review Pantheon's Software Evaluation Licensing Terms for more information about access to our software.
A key-value pair that should not be exposed to the general public, typically something like a password, API key, or the contents of a peer-to-peer cryptographic certificate. SSL certificates that your site uses to serve pages are out of scope of this process and are managed by the dashboard in a different place. See the documentation for SSL certificates for details.
This is a field on the secret record. It defines the usage for this secret and how it is consumed. Current types are:
-
runtime
: this secret will be used to retrieve it in application runtime using API calls to the secret service. This type is not yet in use in Early Access, but will be the recommended way to set information like API keys for third-party integrations in your application. -
env
: this secret will be used to set environment variables in the application runtime. This type is not yet in use in Early Access. -
composer
: this secret type is used for composer authentication to private packages. -
file
: this type allows you to store files in the secrets. This type is not yet in use in Early Access.
Note that you can only set one type per secret and this cannot be changed later (unless you delete and recreate the secret).
This is a field on the secret record. It defines the components that have access to the secret value. Current scopes are:
-
ic
: this secret will be readable by the Integrated Composer runtime. You should use this scope to get access to your private repositories. -
web
: this secret will be readable by the application runtime. -
user
: this secret will be readable by the user. This scope should be set if you need to retrieve the secret value at a later stage.
Note that you can set multiple scopes per secret, but scopes cannot be changed later (unless you delete and recreate the secret).
Secrets are currently either owned by a site or an organization. Within that owning entity, the secret may have zero or more environment overrides.
This is a secret set for a specific site using the site ID. Based on the type and scope, this secret will be loaded on the different scenarios that will be supported by Secrets in Pantheon.
This is a secret set not for a given site but for an organization. This secret will be inherited by ALL sites OWNED by this organization.
Note: Secrets owned by Supporting Organizations won't apply to sites they support. Only the Owner organization's secrets will apply.
In some cases it will be necessary to have different values for the secret when that secret is accessed in different Pantheon environments. You may set an environment override value for any existing secret value.
Note: If the secret does not exist, there is no secret environment to override, and you will get an error.
classDiagram
OrganizationSecretAPIPassword --> SiteSecretAPIPassword
SiteSecretAPIPassword --> IntegratedComposerAPIPassword : no overrides
OrganizationSecretAPIPassword : string name apipassword
OrganizationSecretAPIPassword : string value ball00n
SiteSecretAPIPassword : Inherits value from Org
SiteSecretAPIPassword : No Overrides
IntegratedComposerAPIPassword: value ball00n
OrganizationSecretOverrideExample --> SiteSecretOverrideExample
SiteSecretOverrideExample --> SiteSecretOverrideExampleDev : default value
SiteSecretOverrideExample --> SiteSecretOverrideExampleTest : env override value
SiteSecretOverrideExample --> SiteSecretOverrideExampleLive : env override value
OrganizationSecretOverrideExample : string name apipassword
OrganizationSecretOverrideExample : string value ball00n
SiteSecretOverrideExample : Inherits value from Org
SiteSecretOverrideExample : No Site Overrides
SiteSecretOverrideExampleDev: value ball00n
SiteSecretOverrideExampleDev: defaultValue()
SiteSecretOverrideExampleTest: value ball00n2
SiteSecretOverrideExampleTest: overridden()
SiteSecretOverrideExampleLive: value ball00n3
SiteSecretOverrideExampleLive: overridden()
When a given runtime (e.g. Integrated Composer or an environment php runtime) fetches secrets for a given site (and env), the process will be as follows:
-
Fetch secrets for site (of the given type and scopes).
-
Apply environment overrides (if any) based on the requesting site environment.
-
If the site is owned by an organization:
-
Fetch the organization secrets.
-
Apply environment overrides (if any) based on the requesting site environment.
-
Merge the organization secrets with the site secrets (the following example will describe this process in more detail).
-
Let's go through this with an example: assume you have a site named my-site
which belongs to an organization my-org
. You also have another site my-other-site
which belongs to your personal Pantheon account.
When Integrated Composer attempts to get secrets for my-other-site
it will go like this:
- Get the secrets of scope
ic
formy-other-site
. - Apply environment overrides for the current environment (see Note below).
- Look at
my-other-site
owner. In this case, it is NOT an organization so there are no organization secrets to merge. - Process the resulting secrets to make them available to Composer.
On the other hand, when Integrated Composer attempts to get secrets for my-site
, it will go like this:
- Get the secrets of scope
ic
formy-site
. - Apply environment overrides for the current environment (see Note below).
- Look at the site owner. It determines it is the organization
my-org
. - Get the secrets for the organization
my-org
with scopeic
. - Apply the environment overrides to those secrets for the current environment (see Note below).
- Merge the resulting organization secrets with the site secrets with the following caveats:
- Site secrets take precedence over organization secrets. This means that the value for site-owned secret named
foo
will be used instead of the value for an org-owned secret with the same namefoo
. - Only the secrets for the OWNER organization are being merged. If the site has a Supporting Organization, it will be ignored.
- Site secrets take precedence over organization secrets. This means that the value for site-owned secret named
- Process the resulting secrets to make them available to Composer.
Note: Due to platform design, the "environment" for Integrated Composer will always be either dev
or a multidev. It will never be test
or live
. Therefore we do not recommend using environment overrides for Composer access. The primary use-case for environment overrides is for the CMS key-values and environment variables that need to be different between your live and non-live environments.
Secrets Manager requires the following:
- A Pantheon account
- A site that uses Integrated Composer and runs PHP >= 8.0
- Terminus 3.0+
Terminus 3.x has built in plugin management.
Run the command below to install Terminus Secrets Manager.
terminus self:plugin:install terminus-secrets-manager-plugin
The secrets set
command takes the following format:
Name
Value
Type
One or more scopes
Run the command below to set a new secret in Terminus:
terminus secret:site:set <site> <secret-name> <secret-value>
[notice] Success
terminus secret:site:set <site> file.json "{}" --type=file
[notice] Success
terminus secret:site:set <site> <secret-name> --scope=user,ic
[notice] Success
Note: If you do not include a type
or scope
flag, these values will be set to the defaults (runtime
and user
respectively).
Run the command below to update an existing secret in Terminus:
terminus secret:site:set <site> <secret-name> <secret-value>
[notice] Success
Note: When updating an existing secret, type
and scope
should NOT be passed as they are immutable. You should delete and recreate the secret if you need to update those properties.
Add or update an environment override for an existing secret in Terminus:
terminus secret:site:set <site>.<env> <secret-name> <secret-value>
[notice] Success
Note: You can add an environment override only to existing secrets; otherwise, it will fail.
The secrets list
command provides a list of all secrets available for a site. The following fields are available:
Name
Scope
Type
Value
Environment Override Values
Org Values
Note that the value
field will contain a placeholder value unless the user
scope was specified when the secret was set.
Run the command below to list a site’s secrets:
terminus secret:site:list <site>
------------- ------------- ---------------------------
Secret name Secret type Secret value
------------- ------------- ---------------------------
secret-name env secrets-content
------------- ------------- ---------------------------
terminus secret:site:list <site> --fields="*"
---------------- ------------- ------------------------------------------ --------------- ----------------------------- --------------------
Secret name Secret type Secret value Secret scopes Environment override values Org values
---------------- ------------- ------------------------------------------ --------------- ----------------------------- --------------------
foo env *** web, user
foo2 runtime bar2 web, user default=barorg
foo3 env dummykey web, user live=sendgrid-live
---------------- ------------- ------------------------------------------ --------------- ----------------------------- --------------------
The secrets delete
command will remove a secret and all of its overrides.
Run the command below to delete a secret:
terminus secret:site:delete <site> <secret-name>
[notice] Success
Run the command below to delete an environment override for a secret:
terminus secret:site:delete <site>.<env> <secret-name>
[notice] Success
The secrets local-generate
command will generate a json file useful for local development emulation of secrets.
Run the command below to get a json file:
terminus secret:site:local-generate <site> --filepath=./secrets.json
[notice] Secrets file written to: ./secrets.json. Please review this file and adjust accordingly for your local usage.
The secrets set
command takes the following format:
Name
Value
Type
One or more scopes
Run the command below to set a new secret in Terminus:
terminus secret:org:set <org> <secret-name> <secret-value>
[notice] Success
terminus secret:org:set <org> file.json "{}" --type=file
[notice] Success
terminus secret:org:set <org> <secret-name> --scope=user,ic
[notice] Success
Note: If you do not include a type
or scope
flag, their defaults will be runtime
and user
respectively.
Run the command below to update an existing secret in Terminus:
terminus secret:org:set <org> <secret-name> <secret-value>
[notice] Success
Note: When updating an existing secret, type
and scope
should NOT be passed as they are immutable. You should delete and recreate the secret if you need to update those properties.
Add or update an environment override for an existing secret in Terminus:
terminus secret:org:set --env=<env> <org> <secret-name> <secret-value>
[notice] Success
Note: You can add an environment override only to existing secrets; otherwise, it will fail.
The secrets list
command provides a list of all secrets available for an organization. The following fields are available:
Name
Scope
Type
Value
Environment Override Values
Note that the value
field will contain a placeholder value unless the user
scope was specified when the secret was set.
Run the command below to list a site’s secrets:
terminus secret:org:list <org>
------------- ------------- ---------------------------
Secret name Secret type Secret value
------------- ------------- ---------------------------
secret-name env secrets-content
------------- ------------- ---------------------------
terminus secret:org:list <org> --fields="*"
---------------- ------------- ------------------------------------------ --------------- -----------------------------
Secret name Secret type Secret value Secret scopes Environment override values
---------------- ------------- ------------------------------------------ --------------- -----------------------------
foo env bar web, user
foo2 runtime bar2 web, user
foo3 env dummykey web, user live=sendgrid-live
---------------- ------------- ------------------------------------------ --------------- -----------------------------
The secrets delete
command will remove a secret and all of its overrides.
Run the command below to delete a secret:
terminus secret:org:delete <org> <secret-name>
[notice] Success
Run the command below to delete an environment override for a secret:
terminus secret:org:delete --env=<env> <org> <secret-name>
[notice] Success
Run terminus list secret
for a complete list of available commands. Use terminus help to get help with a specific command.
The service supports up to 3 requests per second per user through Terminus. If you hit that limit, the API will return a 429
error code and the plugin will throw an error.
The PHP SDK and pantheon_get_secret()
function are not affected by this rate limiting.
You must configure your private repository and provide an authentication token before you can use the Secrets Manager Terminus plugin with Integrated Composer. You could use either of the following mechanisms to setup this authentication.
-
Generate a Github token. The Github token must have all "repo" permissions selected.
NOTE: Check the repo box that selects all child boxes. Do not check all child boxes individually as this does not set the correct permissions.
-
Set the secret value to the token via terminus:
terminus secret:site:set <site> github-oauth.github.com <github_token> --type=composer --scope=user,ic
-
Add your private repository to the
repositories
section ofcomposer.json
:{ "type": "vcs", "url": "https://github.com/your-organization/your-repository-name" }
Your repository should contain a
composer.json
that declares a package name in itsname
field. If it is a WordPress plugin or a Drupal module, it should specify atype
ofwordpress-plugin
ordrupal-module
respectively. For these instructions, we will assume your package name isyour-organization/your-package-name
. -
Require the package defined by your private repository's
composer.json
by either adding a new record to therequire
section of the site'scomposer.json
or with acomposer require
command:composer require your-organization/your-package-name
-
Commit your changes and push to Pantheon.
-
Generate a GitLab token. Ensure that
read_repository
scope is selected for the token. -
Set the secret value to the token via Terminus:
terminus secret:site:set <site> gitlab-oauth.gitlab.com <gitlab_token> --type=composer --scope=user,ic
-
Add your private repository to the
repositories
section ofcomposer.json
:{ "type": "vcs", "url": "https://gitlab.com/your-group/your-repository-name" }
Your repository should contain a
composer.json
that declares a package name in itsname
field. If it is a WordPress plugin or a Drupal module, it should specify atype
ofwordpress-plugin
ordrupal-module
respectively. For these instructions, we will assume your package name isyour-organization/your-package-name
. -
Require the package defined by your private repository's
composer.json
by either adding a new record to therequire
section of the site'scomposer.json
or with acomposer require
command:composer require your-group/your-package-name
-
Commit your changes and push to Pantheon.
-
Generate a Bitbucket oauth consumer. Ensure that Read repositories permission is selected for the consumer. Also, set the consumer as private and put a (dummy) callback URL.
-
Set the secret value to the consumer info via Terminus:
terminus secret:site:set <site> bitbucket-oauth.bitbucket.org "<consumer_key> <consumer_secret>" --type=composer --scope=user,ic
-
Add your private repository to the
repositories
section ofcomposer.json
:{ "type": "vcs", "url": "https://bitbucket.org/your-organization/your-repository-name" }
Your repository should contain a
composer.json
that declares a package name in itsname
field. If it is a WordPress plugin or a Drupal module, it should specify atype
ofwordpress-plugin
ordrupal-module
respectively. For these instructions, we will assume your package name isyour-organization/your-package-name
. -
Require the package defined by your private repository's
composer.json
by either adding a new record to therequire
section of the site'scomposer.json
or with acomposer require
command:composer require your-organization/your-package-name
-
Commit your changes and push to Pantheon.
You may create a COMPOSER_AUTH json
and make it available via the COMPOSER_AUTH
environment variable if you have multiple private repositories on multiple private domains.
Composer has the ability to read private repository access information from the environment variable: COMPOSER_AUTH
. The COMPOSER_AUTH
variables must be in a specific JSON format.
Format example:
#!/bin/bash
read -e COMPOSER_AUTH_JSON <<< {
"http-basic": {
"github.com": {
"username": "my-username1",
"password": "my-secret-password1"
},
"repo.example2.org": {
"username": "my-username2",
"password": "my-secret-password2"
},
"private.packagist.org": {
"username": "my-username2",
"password": "my-secret-password2"
}
}
}
EOF
`terminus secret:site:set ${SITE_NAME} COMPOSER_AUTH ${COMPOSER_AUTH_JSON} --type=env --scope=user,ic`
If you want to use Pantheon Secrets in your Drupal application through the Key module, you should use the Pantheon Secrets module.