diff --git a/source/content/drupal-updates.md b/source/content/drupal-updates.md index 569f42e33d..c9a24cc700 100644 --- a/source/content/drupal-updates.md +++ b/source/content/drupal-updates.md @@ -53,7 +53,9 @@ The critical commands are: terminus drush my-drupal-8-site.dev -- migrate-upgrade --legacy-db-key=drupal_7 --configure-only --legacy-root=https://drupal7.example.com ``` -This command configures (but does not run) the migrations from Drupal 7 to Drupal 8. In this example, the Drupal 8 site is named `my-drupal-8-site` and the command is running on the `dev` environment. The `--legacy-db-key` parameter indicates how to get the login credentials to the source Drupal 7 database. In our example, we use the [Terminus secrets](https://github.com/pantheon-systems/terminus-secrets-plugin) plugin to supply the connection info. [See our blog post for more information on how this flag is used](https://pantheon.io/blog/running-drupal-8-data-migrations-pantheon-through-drush). The `--legacy-root` flag lets Drupal 8 know from where it can grab images and other uploaded media assets. +This command configures (but does not run) the migrations from Drupal 7 to Drupal 8. In this example, the Drupal 8 site is named `my-drupal-8-site` and the command is running on the `dev` environment. The `--legacy-db-key` parameter indicates how to get the login credentials to the source Drupal 7 database. + +In our example, we use the [Terminus secrets Manager Plugin](https://github.com/pantheon-systems/terminus-secrets-manager-plugin) plugin to supply the connection info. [See our blog post for more information on how this flag is used](https://pantheon.io/blog/running-drupal-8-data-migrations-pantheon-through-drush). The `--legacy-root` flag lets Drupal 8 know from where it can grab images and other uploaded media assets. The following command generates a report on how many items have been imported by each migration: diff --git a/source/content/guides/environment-configuration/02-read-environment-config.md b/source/content/guides/environment-configuration/02-read-environment-config.md index 1a481dfed0..90e5cef189 100644 --- a/source/content/guides/environment-configuration/02-read-environment-config.md +++ b/source/content/guides/environment-configuration/02-read-environment-config.md @@ -168,122 +168,11 @@ array(63) { It is not possible to set environment variables on Pantheon. However, there are three common solutions you can use instead. -### Terminus Secrets Plugin +### Terminus Secrets Manager Plugin -You can use the [Terminus Secrets Plugin](https://github.com/pantheon-systems/terminus-secrets-plugin) to write the secrets to a JSON file in the private file system. Your PHP will look similar to the code example below. This example will help you get started, however, you must modify the third line for the key you want to configure. You can also modify the `secrets.json` file name, although we recommend you provide the file with a name you will recognize for secrets management. +You can use the [Terminus Secrets Manager Plugin](https://github.com/pantheon-systems/terminus-secrets-manager-plugin) to write the secrets to Pantheon's secure storage system. The secrets are encrypted at rest and follow all standard practices for the storing of sensitive values. - - - - -1. Modify and use the code example below to write secrets. - -```bash -$secrets_json_text = file_get_contents('/files/private/secrets.json'); -$secrets_data = json_decode($secrets_json_text, TRUE); -define('EXAMPLE_API_KEY', $secrets_data['example_api_key']); -``` - - - - - -1. Modify and use the code example below to write secrets. - -```bash -$secrets_json_text = file_get_contents('/files/private/secrets.json'); -$secrets_data = json_decode($secrets_json_text, TRUE); -$config['example_integration.settings']['apikey'] = $secrets_data['example_api_key']; -``` - - - - - -### Manual File Creation - -You can manually create and add files to the `/files/private` directory for scenarios that are not supported by the Terminus Secrets plugin. For example, when secrets in the Dev and Live environments are different. - -1. Create your files manually in the `/files/private` directory for each case required, for example: - - - `/files/private/dev.secrets.json` - - `/files/private/test.secrets.json` - - `/files/private/live.secrets.json` - -1. Update your PHP file using the code examples below as a reference. - - - Note that the code below uses SendGrid as an example. You will need to modify the code for the specific key you are configuring. - - - - - -1. Add the code to your `wp-config.php` file and modify it as necessary for the specific key you are configuring: - -```php -if ( ! empty( $_ENV['PANTHEON_ENVIRONMENT'] ) ) { - switch( $_ENV['PANTHEON_ENVIRONMENT'] ) { - case 'live': - // keys for production env - $secrets_filename = 'live.secrets.json'; - break; - case 'test': - // keys for staging env - $secrets_filename = 'test.secrets.json'; - break; - default: - // keys for dev and multidev envs - $secrets_filename = 'dev.secrets.json'; - break; - } - if (isset($secrets_filename)) { - $secrets_json_text = file_get_contents('/files/private/' . $secrets_filename); - $secrets_data = json_decode($secrets_json_text, TRUE); - - define('SENDGRID_API_KEY', $secrets_data['sendgrid_api_key']); - define('SOME_OTHER_OPTION', $secrets_data['other_key_example']); -} -``` - - - - - -1. Add the code below to your `settings.php` file and modify it as necessary for the specific key you are configuring: - -```php - if ( ! empty( $_ENV['PANTHEON_ENVIRONMENT'] ) ) { - switch( $_ENV['PANTHEON_ENVIRONMENT'] ) { - case 'live': - // keys for production env - $secrets_filename = 'live.secrets.json'; - break; - case 'test': - // keys for staging env - $secrets_filename = 'test.secrets.json'; - break; - default: - // keys for dev and multidev envs - $secrets_filename = 'dev.secrets.json'; - break; - } - if (isset($secrets_filename)) { - $secrets_json_text = file_get_contents('/files/private/' . $secrets_filename); - $secrets_data = json_decode($secrets_json_text, TRUE); - - $config['sendgrid_integration.settings']['apikey'] = $secrets_data['sendgrid_api_key']; - $config['some_other_config_override']['value'] = $secrets_data['other_key_example']; - } - ``` -``` - - - - - -### Lockr - -You can use [Lockr](/guides/lockr) for maximum site security. Lockr provides a simple-to-use developer interface with a scalable cloud key management system. Review the [Install Lockr via the Lockr Terminus Plugin](/guides/lockr#install-lockr-via-the-lockr-terminus-plugin) guide section for installation steps. +Please see the README in the plugin's repository for the most up-to-date code examples. ## More Resources diff --git a/source/content/guides/secrets/01-introduction.md b/source/content/guides/secrets/01-introduction.md new file mode 100644 index 0000000000..4f8a784e42 --- /dev/null +++ b/source/content/guides/secrets/01-introduction.md @@ -0,0 +1,67 @@ +--- +title: Pantheon Secrets Guide +subtitle: Introduction +description: Securely store secrets in the Pantheon Platform. +contributors: [stovak] +contenttype: [guide] +innav: [true] +categories: [secrets] +cms: [drupal, wordpress] +audience: [development] +product: [secrets] +integration: [--] +tags: [reference, cli, local, terminus, workflow] +permalink: docs/guides/secrets +reviewed: "2024-08-22" +showtoc: true +--- +Pantheon Secrets is key to maintaining industry best practices for secure builds and application implementation. This feature provides a convenient mechanism for you to manage your secrets and API keys directly on the Pantheon platform. + +This guide covers features and use cases of the Pantheon Secrets feature; it could also be referred as Secrets Manager because that is the Terminus plugin name. + +## Features +Key features include: +* **Secure**: Secrets are encrypted at rest and securely hosted on Pantheon. +* **Easy to use**: Create and update secrets via Terminus. +* **Governable**: Secrets can be set at organization level and shared with all the sites owned by that organization. +* **Overridable**: Secrets can be overridden at environment level when needed. + +This feature also supports: +* The use of private repositories in Integrated Composer builds. +* The ability to set a `COMPOSER_AUTH` environment variable and/or a Composer `auth.json` authentication file. +* The ability to define the degree of secrecy for each managed item. + +## Access & Availability +This feature is available for anyone to use today at no additional cost. Currently released for Limited Availability, the [Terminus Secrets Manager Plugin](https://github.com/pantheon-systems/terminus-secrets-manager-plugin) will eventually be merged into Terminus core once released for General Availability in the future. + +### Installation +How to get started and use this feature: +1. [Install & authenticate Terminus](/terminus/install) if you have not done so already. +1. Install the [Terminus Secrets Manager Plugin](https://github.com/pantheon-systems/terminus-secrets-manager-plugin): + + ```bash{promptUser: user} + terminus self:plugin:install terminus-secrets-manager-plugin + ``` + +1. You can now use the newly installed Terminus commands, such as `secret:site:set`, to manage secrets securely on Pantheon. + +To see all available commands added by this plugin, refer to the [plugin's README file](https://github.com/pantheon-systems/terminus-secrets-manager-plugin?tab=readme-ov-file#site-secrets-commands). + +### Older plugin now deprecated +The new [Terminus Secrets Manager Plugin](https://github.com/pantheon-systems/terminus-secrets-manager-plugin) replaces the older [Terminus Secrets Plugin](https://github.com/pantheon-systems/terminus-secrets-plugin). The key differences are: + +- The new Terminus Secrets Manager Plugin stores secrets in an encrypted backend service. +- The older secrets plugin simply writes unencrypted values to a json file in `/files/private`. + +Once the Pantheon Secrets service becomes generally available and merged into Terminus core, the older `terminus-secrets-plugin` will be discontinued. If you use the older plugin to manage secrets today, we strongly encourage you to upgrade your security and experience by adopting this new feature. + +## Support +The [Terminus Secrets Manager Plugin](https://github.com/pantheon-systems/terminus-secrets-manager-plugin), [PHP Secrets SDK](https://github.com/pantheon-systems/customer-secrets-php-sdk), and [Pantheon Secrets](https://github.com/pantheon-systems/pantheon_secrets) Drupal module are open source. You can view the projects, file issues and feature requests, and contribute in their respective repositories on GitHub. + +* [Terminus Secrets Manager Plugin](https://github.com/pantheon-systems/terminus-secrets-manager-plugin) +* [Secrets SDK](https://github.com/pantheon-systems/customer-secrets-php-sdk) +* Pantheon Secrets Drupal module + * [github repo](https://github.com/pantheon-systems/pantheon_secrets) for issues & PRs + * [drupal.org](https://www.drupal.org/project/pantheon_secrets) for releases + +[Contact Support](https://dashboard.pantheon.io/#support/support/all) if you have questions or need help with Terminus. diff --git a/source/content/guides/secrets/02-secrets-overview.md b/source/content/guides/secrets/02-secrets-overview.md new file mode 100644 index 0000000000..5123b052eb --- /dev/null +++ b/source/content/guides/secrets/02-secrets-overview.md @@ -0,0 +1,113 @@ +--- +title: Pantheon Secrets Guide +subtitle: Secrets Overview +description: Gaining familiarity with some concepts about Pantheon Secrets will help you make the most of this feature. +contributors: [stovak] +contenttype: [guide] +innav: [true] +categories: [secrets] +cms: [drupal, wordpress] +audience: [development] +product: [secrets] +integration: [--] +tags: [reference, cli, local, terminus, workflow] +permalink: docs/guides/secrets/overview +reviewed: "2024-08-22" +showtoc: true +--- + +

A secret is a key-value pair that should not be exposed to the general public, typically something like a password, API key, or other sensitive information that should not be added to version control.

+ +Each secret's value can be no larger than 16k (16384 Bytes) + +## Secret Type + +This represents how the secret is used. A secret can only have one type. + +Current types are: + + * `runtime`: This secret type can be retreived directly from your application code using the `pantheon_get_secret()` function. This is the recommended type if you want your application to be able to use the secret while it's operating. + + * `env`: This type is used to set environment variables. Environment variables are currently only supported for Integrated Composer builds; setting environment variables on the application server is unsupported. + + * `composer`: This secret type is specifically used for authentication when pulling Composer packages from private repositories. This is the recommended method for installing private composer packages. + + + + You can only set one type per secret and this cannot be changed later (unless you delete and recreate the secret). + + + + +## Secret Scope + +

A secret's scope is the answer to the question "Where is the secret's value available?". Once set, a secret's scope cannot be changed. The secret must be deleted and recreated to change its scope.

+ + * `ic`: This secret will be readable during Integrated Composer builds. 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 want to see the value of your secret displayed when listing site secrets with Terminus. The value for secrets without the the user scope is redacted in the Terminus secrets list. + +## Owning Entity +

Secrets are either owned by a site or an organization. Within that owning entity, the secret may have zero or more environment overrides.

+ +### Organization-owned secrets +Organization-owned secrets are available to every site and environment that are associated with the owning organization. A common use-cases is for a CI system and infrastructure that's shared among all sites in an organization. Note that secrets from "Supporting" Organizations are explicitly ***not shared*** with the sites they support. Sites receive secret key/value pairs from their Primary Organization only. + +### Site-owned secrets +Site-owned secrets are available to the site and all of its environments. A common use-case is Github tokens that a site's composer build can use to access private repos referenced in the composer file. + +### Environment override +Environment overrides provide overrides to a secret value for a specific environment. A common use case for this are API keys that are different in production and non-production environments. + + + +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. + + + + +## Value Resolution + +1. Organization values have the lowest priority. They form the base value that is used when there is no more specific value provided for the site or environment. + +3. Site values will replace the organization values when present. To return the secret to it's organization value, simply delete the site value. + +4. Environmental overrides have the highest priority. If the override exists, it will become the value provided to the calling function. + +### The life of a secret + +When a given runtime (e.g. Integrated Composer or an environment PHP runtime) fetches secrets for a given site (and environment), 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). + +### Example Value Resolution +Given you have an integrated composer site named `my-org-site` which belongs to an organization `my-org`, and you also have another integrated composer site named `my-personal-site` which belongs to your personal Pantheon account. + +When Integrated Composer attempts to get secrets for `my-personal-site` it will work like this: +- Get the secrets of scope `ic` for `my-personal-site`. +- Apply environment overrides for the current environment. +- Look at `my-personal-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-org-site`, it will work like this: +- Fetch the secrets in the scope of `ic` for `my-org-site`. +- Apply environment overrides for the current environment. +- Look at the site owner. The organization `my-org` is identified. +- Fetch the secrets for the organization `my-org` with scope `ic`. +- Apply the environment overrides to those secrets for the current environment. +- 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 name `foo`. + - Only the secrets for the OWNER organization are being merged. If the site has a Supporting Organization, it will be ignored. +- Process the resulting secrets to make them available to Composer. diff --git a/source/content/guides/secrets/04-php.md b/source/content/guides/secrets/04-php.md new file mode 100644 index 0000000000..4cd44ea260 --- /dev/null +++ b/source/content/guides/secrets/04-php.md @@ -0,0 +1,76 @@ +--- +title: Pantheon Secrets Guide +subtitle: PHP Usage +description: How to read Pantheon Secrets from code. +contributors: [stovak] +contenttype: [guide] +innav: [true] +categories: [secrets] +cms: [drupal, wordpress] +audience: [development] +product: [secrets] +integration: [--] +tags: [reference, cli, local, terminus, workflow] +permalink: docs/guides/secrets/php +reviewed: "2024-08-22" +showtoc: true +--- + +## Reading secrets from PHP +Secrets can be read, updated, created, and deleted via the [Terminus Secrets Manager Plugin](https://github.com/pantheon-systems/terminus-secrets-manager-plugin). WordPress and Drupal however, can only read secrets at runtime - there is no way to modify secrets via the application or in code. + +Secrets must have the scope `web` to be visible from your application. Secrets are cached in the server for 15 minutes, so you must wait for a while after modifying secret values before they will be available for use. This cache is also encrypted at rest. + +Note: this also applies to quicksilver scripts. + +### Use the pantheon_get_secret PHP function + +The function `pantheon_get_secret()` may be used to fetch the value of a single secret. + +```php +if ( function_exists('pantheon_get_secret') ) { + $secret_value = pantheon_get_secret("SECRET_NAME"); +} +``` + +## WordPress detailed example +In this guide we will go over an end-to-end example on how to setup secrets for a given site and how to read those secrets in `wp-config.php`. For this example, we will use the [WP Mail SMTP](https://wordpress.org/plugins/wp-mail-smtp/) plugin to setup SendGrid. + +### Prerequisites + +- Make sure you have access to a WordPress site on Pantheon. + +- Make sure you have [Terminus installed](https://docs.pantheon.io/terminus/install#install-terminus) on your local machine. + +- Install the [Terminus Secrets Manager Plugin](https://github.com/pantheon-systems/terminus-secrets-manager-plugin#installation). + +### Steps + +1. Install and activate the [WP Mail SMTP](https://wordpress.org/plugins/wp-mail-smtp/) plugin. +1. Make sure your SendGrid account is correctly configured and allows sending email. + +1. Create a SendGrid API key by following the [SendGrid instructions](https://docs.sendgrid.com/ui/account-and-settings/api-keys#creating-an-api-key). + +1. Store the API key as a site secret: + + ```bash{promptUser: user} + terminus secret:site:set sendgrid_api --scope=web --type=runtime + ``` + + As a best practice, the non-production environments should be the default and then override that value with a [secret environment override](/guides/secrets/overview#environment-override) to change the API key for the live environment (for example, if you want to use different SendGrid accounts for live and dev environments). +1. Add the following to `wp-config.php`, replacing placeholder values (e.g., `example@example.com` and `Example From Name`): + + ```php + define( 'WPMS_ON', true ); // True turns on the WPMS constants for usage below, false turns it off. + define( 'WPMS_MAIL_FROM', 'example@example.com' ); + define( 'WPMS_MAIL_FROM_NAME', 'Example From Name'); + define( 'WPMS_MAILER', 'sendgrid' ); + if ( function_exists('pantheon_get_secret') ) { + define( 'WPMS_SENDGRID_API_KEY', pantheon_get_secret( 'sendgrid_api' ) ); + } + ``` + +1. Go to the SendGrid email test page (`/wp-admin/admin.php?page=wp-mail-smtp-tools&tab=test`) and test your SendGrid integration by sending a test email. + +## More Resources +For advanced use cases, you may consider leveraging the [Secrets SDK](https://github.com/pantheon-systems/customer-secrets-php-sdk) library as an alternative to the `pantheon_get_secret` function. diff --git a/source/content/guides/secrets/05-drupal.md b/source/content/guides/secrets/05-drupal.md new file mode 100644 index 0000000000..070cd01c48 --- /dev/null +++ b/source/content/guides/secrets/05-drupal.md @@ -0,0 +1,97 @@ +--- +title: Pantheon Secrets Guide +subtitle: Drupal Key Usage +description: How to configure Sendgrid using Pantheon Secrets with Drupal's Key module. +contributors: [stovak] +contenttype: [guide] +innav: [true] +categories: [secrets] +cms: [drupal, wordpress] +audience: [development] +product: [secrets] +integration: [--] +tags: [reference, cli, local, terminus, workflow] +permalink: docs/guides/secrets/drupal +reviewed: "2024-08-22" +showtoc: true +--- + +If you want to use Pantheon Secrets in your Drupal application through the [Key module](https://www.drupal.org/project/key), you should use the [Pantheon Secrets](https://www.drupal.org/project/pantheon_secrets) module. + +## Pantheon Secrets detailed example + +In this guide we will go over an end-to-end example on how to setup secrets for a given site and how to use those secrets on a module that integrates with the Key module. For this example, we will use the [SendGrid API](https://www.drupal.org/project/sendgrid_api) and [SendGrid Mailer](https://www.drupal.org/project/sendgrid_mailer) modules. + +### Prerequisites + +- Make sure you have access to a Drupal 9.4 or greater site running PHP 8.0 or above hosted on Pantheon. + +- Make sure you have [Terminus installed](https://docs.pantheon.io/terminus/install#install-terminus) on your local machine. + +- Install the [Terminus Secrets Manager Plugin](https://github.com/pantheon-systems/terminus-secrets-manager-plugin#installation). + +### Steps + +1. Install the required modules in your Drupal site and push the changes to Pantheon: + ```bash{promptUser: user} + composer require drupal/pantheon_secrets drupal/sendgrid_api drupal/sendgrid_mailer + git add composer.json composer.lock + git commit -m "Add Pantheon Secrets and SendGrid modules." + git push + ``` + +1. Enable the modules: + ```bash{promptUser: user} + terminus drush . -- en -y pantheon_secrets sendgrid_api sendgrid_mailer + ``` + +1. Make sure your SendGrid account is correctly configured and allows sending email. + +1. Create a SendGrid API key by following the [SendGrid instructions](https://docs.sendgrid.com/ui/account-and-settings/api-keys#creating-an-api-key). + +1. Store the API key as a site secret: + ```bash{promptUser: user} + terminus secret:site:set sendgrid_api --scope=web --type=runtime + ``` + + As a best practice, the non-production environments should be the default and then override that value with a [secret environment override](/guides/secrets/overview#environment-override) to change the API key for the live environment (for example, if you want to use different SendGrid accounts for live and dev environments). + +1. Add the Key entity in one of the different available ways: + + * **Option 1: Manually** + + Go to `/admin/config/system/keys` and click **Add key**. Select Pantheon Secret as the key provider and your secret name from the dropdown (make sure you select "SendGrid" as the Key type and "Pantheon" as the Key provider) + + ![Screenshot of creating a new Key entity with type "Sendgrid" and provider "Pantheon"](../../../images/guides/secrets/add-key.png) + + * **Option 2: Sync Keys via Drupal Admin** + + Go to `/admin/config/system/keys/pantheon` and click on the "Sync Keys" button to get all of the available secrets into Key entities. + + ![Screenshot of Sync Pantheon Secrets page in Drupal UI](../../../images/guides/secrets/sync-keys.png) + + Then, go to `/admin/config/system/keys` to edit the `sendgrid_api` Key and change the type to "SendGrid". + + * **Option 3: Sync Keys via Terminus** + + Use the provided Drush command to sync all of your secrets into Key entities: + + ```bash{promptUser: user} + terminus drush . -- pantheon-secrets:sync + ``` + + Then, go to `/admin/config/system/keys` to edit the `sendgrid_api` Key and change the type to "SendGrid". + +1. Go to the SendGrid API Configuration page (`/admin/config/services/sendgrid`) and select your Key item. + + ![Screenshot of Sendgrid API Configuration page in Drupal UI](../../../images/guides/secrets/sendgrid-config.png) + +1. Make sure your site "Email Address" (`/admin/config/system/site-information`) matches a verified Sender Identity in SendGrid. + +1. Go to the Default Mail System Configuration page (`/admin/config/system/mailsystem`) and set `Formatter` and `Sender` to `SendGrid Mailer`. + +1. Go to the SendGrid email test page (`/admin/config/services/sendgrid/test`) and test your SendGrid integration by sending a test email. + + ![Screenshot of Sendgrid email test page in Drupal UI](../../../images/guides/secrets/sendgrid-email-test.png) + +1. The email should get to your inbox. Enjoy! diff --git a/source/content/guides/secrets/06-composer.md b/source/content/guides/secrets/06-composer.md new file mode 100644 index 0000000000..2697b7ebf1 --- /dev/null +++ b/source/content/guides/secrets/06-composer.md @@ -0,0 +1,154 @@ +--- +title: Pantheon Secrets Guide +subtitle: Integrated Composer Usage +description: How to use Pantheon Secrets with Pantheon's Integrated Composer. +contributors: [stovak] +contenttype: [guide] +innav: [true] +categories: [secrets] +cms: [drupal, wordpress] +audience: [development] +product: [secrets] +integration: [--] +tags: [reference, cli, local, terminus, workflow] +permalink: docs/guides/secrets/composer +reviewed: "2024-08-22" +showtoc: true +--- + +## Using secrets with Integrated Composer + +### Mechanism 1: OAuth composer authentication (recommended) +If your Composer-based dependency is private, and the repository supports OAuth authentication, storing your token as a secret in the Pantheon Secrets API is a simpler way to allow access to those private repositories. + + + + + +1. [Generate a GitHub token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-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. + + ![image](https://user-images.githubusercontent.com/87093053/191616923-67732035-08aa-41c3-9a69-4d954ca02560.png) + +1. Set the secret value to the token via terminus: + + ```bash{promptUser: user} + terminus secret:site:set github-oauth.github.com --type=composer --scope=ic + ``` + +1. Add your private repository to the `repositories` section of `composer.json`: + + ```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 its `name` field. It should specify a `type` like `wordpress-plugin` or `drupal-module` for example. For these instructions, we will assume your package name is `your-organization/your-package-name`. + +1. Require the package defined by your private repository's `composer.json` by either adding a new record to the `require` section of the site's `composer.json` or with a `composer require` command: + + ```bash{promptUser: user} + composer require your-organization/your-package-name + ``` + +1. Commit your changes and push to Pantheon. + + + + + +1. [Generate a GitLab token](https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html). Ensure that `read_repository` scope is selected for the token. + +1. Set the secret value to the token via Terminus: + + ```bash{promptUser: user} + terminus secret:site:set gitlab-oauth.gitlab.com --type=composer --scope=ic + ``` + +1. Add your private repository to the `repositories` section of `composer.json`: + + ```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 its `name` field. It should specify a `type` like `wordpress-plugin` or `drupal-module` for example. For these instructions, we will assume your package name is `your-organization/your-package-name`. + +1. Require the package defined by your private repository's `composer.json` by either adding a new record to the `require` section of the site's `composer.json` or with a `composer require` command: + + ```bash{promptUser: user} + composer require your-group/your-package-name + ``` + +1. Commit your changes and push to Pantheon. + + + + + +1. [Generate a Bitbucket OAuth consumer](https://support.atlassian.com/bitbucket-cloud/docs/use-oauth-on-bitbucket-cloud/). Ensure that Read repositories permission is selected for the consumer. Set the consumer as private and put a (dummy) callback URL. + +1. Set the secret value to the consumer info via Terminus: + ```bash{promptUser: user} + terminus secret:site:set bitbucket-oauth.bitbucket.org " " --type=composer --scope=ic + ``` + +1. Add your private repository to the `repositories` section of `composer.json`: + + ```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 its `name` field. It should specify a `type` like `wordpress-plugin` or `drupal-module` for example. For these instructions, we will assume your package name is `your-organization/your-package-name`. + +1. Require the package defined by your private repository's `composer.json` by either adding a new record to the `require` section of the site's `composer.json` or with a `composer require` command: + + ```bash{promptUser: user} + composer require your-organization/your-package-name + ``` + +1. Commit your changes and push to Pantheon. + + + + + +### Mechanism 2: HTTP Basic Authentication + +In the case where you have a Composer dependency that only supports HTTP Basic Authentication, 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](https://getcomposer.org/doc/articles/authentication-for-private-packages.md#http-basic). + +**Format example:** + +```bash +#!/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=ic +``` diff --git a/source/content/guides/secrets/07-local.md b/source/content/guides/secrets/07-local.md new file mode 100644 index 0000000000..cdb437cae2 --- /dev/null +++ b/source/content/guides/secrets/07-local.md @@ -0,0 +1,70 @@ +--- +title: Pantheon Secrets Guide +subtitle: Local Development Usage +description: Developing locally presents some unique challenges once Pantheon Secrets are built into your workflow. These are some tips to help you get past struggling with trying to reproduced secret behavior while developing locally. +contributors: [stovak] +contenttype: [guide] +innav: [true] +categories: [secrets] +cms: [drupal, wordpress] +audience: [development] +product: [secrets] +integration: [--] +tags: [reference, cli, local, terminus, workflow] +permalink: docs/guides/secrets/local +reviewed: "2024-08-22" +showtoc: true +--- +## Local Environment Usage + +The [Pantheon Secrets SDK](https://github.com/pantheon-systems/customer-secrets-php-sdk) includes a `CustomerSecretsFakeClient` implementation that is used when the SDK runs outside of Pantheon infrastructure. This client uses a secrets JSON file to build the secrets information emulating what happens on the platform using the Secrets service. + +To get this file, you should use the [plugin](https://github.com/pantheon-systems/terminus-secrets-manager-plugin/) `secret:site:local-generate` command and then set an environment variable into your local environment (or docker container if you are running a docker-ized environment) with name `CUSTOMER_SECRETS_FAKE_FILE` and use the absolute path to the file as the value. + + +### LANDO example + +1. To setup this using lando, you should modify your `.lando.yml` like this: + ```yaml + services: + appserver: + overrides: + environment: + CUSTOMER_SECRETS_FAKE_FILE: /app/secrets.json + ``` + +2. Generate the secrets file like this: + ```bash{promptUser: user} + terminus secret:site:local-generate --filepath=./secrets.json + ``` + +3. And rebuild lando application: + ```bash{promptUser: user} + lando rebuild -y + ``` + +Now, you will be able to use your secrets through the SDK. + + +### DDEV example + +1. CD to your ddev root directory. + +2. To setup using DDEV, add the following to your `~/.ddev/config.yml` + ```yaml + web_environment: + - CUSTOMER_SECRETS_FAKE_FILE=./secrets.json + ``` + +3. Generate the secrets file + ```bash{promptUser: user} + terminus secret:site:local-generate --filepath=./secrets.json + ``` + +4. Restart your ddev environment + ```bash{promptUser: user} + ddev restart + ``` + +## Restrictions +For secrets that do not have the "user" scope, the `secret:site:local-generate` command will set the value of the secret to "null". Edit this file and replace the null values with appropriate test values for local development. diff --git a/source/content/guides/secrets/08-troubleshooting.md b/source/content/guides/secrets/08-troubleshooting.md new file mode 100644 index 0000000000..1644b2ea73 --- /dev/null +++ b/source/content/guides/secrets/08-troubleshooting.md @@ -0,0 +1,102 @@ +--- +title: Pantheon Secrets Guide +subtitle: Troubleshooting +description: Securely store secrets in the Pantheon Platform. +contributors: [stovak] +contenttype: [guide] +innav: [true] +categories: [secrets] +cms: [drupal, wordpress] +audience: [development] +product: [secrets] +integration: [--] +tags: [reference, cli, local, terminus, workflow] +permalink: docs/guides/secrets/troubleshooting +reviewed: "2024-08-22" +showtoc: true +--- + +## Default secret value does not exist +Setting an environmental override when no site or organization secret has been set, results in an error like this: + +``` +terminus secret:site:set site.dev mysecretnonexist foobar +[error] An error happened when trying to set the secret. +[error] Secret 'mysecretnonexist' does not exist. You should create the default secret value first. +``` + +A site-level or organization-level secret must be set first before you can set an environmental override. + +## Invalid key name +There are some validations in place for the key name based on the key type. As an example, a secret name of type env must match the following regex: `^[a-zA-Z_][a-zA-Z0-9_]*$`. Failure to comply with those validations results in errors like this: + +``` +terminus secret:site:set site 1nvalid value --type=env + [error] An error happened when trying to set the secret. + [error] Invalid key name '1nvalid': Environment variable names must start with a letter or underscore, and can only contain letters, numbers, and underscores. +``` + +Either make your secret name match the expected pattern or change the type if that’s an option. + +## Integrated Composer Build fails on private packages + +This is the most common error when sites are using secrets and Integrated Composer. This may manifest in different ways and may be caused by different problems. This playbook tries to cover them. + +### Error getting a private package during the IC build + +This is the most common error; an example message associated to this error is: + +``` +Failed to download vendor/package from dist +``` +(where vendor/package may be any private package) + +Some possible causes for this error: + +- **Problem:** Secrets are not correctly set for the site. Secrets for Integrated Composer to use need to be type `composer` and have scope `ic`. Secret types and scopes are covered in the [Basic Concepts](/guides/secrets/02-basic-concepts) documentation. + + **Solution:** ask the client to delete and recreate the secret if scope and type do not match for the given secret name + +- **Problem:** Secret value/token may be expired + + **Solution:** ask the client to set the secret again to an updated value + +- **Problem**: Site may be running on a PHP version below 8.0. If this is the case, there will be a message in the job output: “Skipping setting up secrets as it is not supported in PHP below 8.0” + + **Solution**: Upgrade the client to a supported PHP version. + +- **Problem:** Errors with paid WordPress plugins. + + Example error message associated to this: + "Could not find a license key for ACF PRO. No valid license key could be found" + + Possible causes for this error: + + - This error happens when [https://packagist.org/packages/pivvenit/acf-pro-installer](https://packagist.org/packages/pivvenit/acf-pro-installer) is used and the ACF_PRO_KEY is not available + - Please note that the plugin is no longer supported by the developer as ACF now has built-in composer support. It’s a good idea to switch to the composer-based version. + + **Solution:** + + If the plugin is still in use: + - Look for the secret with name ACF_PRO_KEY, it should be of type env and scope ic. Delete and recreate if type or scope doesn’t match. + - Make sure the site is running PHP >= 8 + +- **Problem:** Error cloning private package via SSH. IC builds + secrets management is intended to clone over https and not over ssh as that would require a ssh key and the process to set things up is way more complex than http auth. + + An example error message associated to this error is: + + ``` + Failed to execute git clone --mirror -- 'git@github.com:biltmoreco/advanced-custom-fields-pro.git' '/home/pantheon-app/.cache/composer/vcs/git-github.com-biltmoreco-advanced-custom-fields-pro.git/' + ``` + + **Solution:** Change the repository definition (in composer.json) to use https instead of ssh. In this example, the repository would be https://github.com/biltmoreco/advanced-custom-fields-pro.git + + +## Rate limiting +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. + +## Still having issues? + +[Contact support](/guides/support/contact-support/) diff --git a/source/content/pivotal-tracker.md b/source/content/pivotal-tracker.md index a2ebe59eb9..6e4d1786bd 100644 --- a/source/content/pivotal-tracker.md +++ b/source/content/pivotal-tracker.md @@ -28,10 +28,10 @@ Be sure to: curl -O https://raw.githubusercontent.com/pantheon-systems/terminus-installer/master/builds/installer.phar && php installer.phar install ``` -- Install the [Terminus Secrets Plugin](https://github.com/pantheon-systems/terminus-secrets-plugin): +- Install the [Terminus Secrets Manager Plugin](https://github.com/pantheon-systems/terminus-secrets-manager-plugin): ```bash{promptUser: user} - curl https://github.com/pantheon-systems/terminus-secrets-plugin/archive/1.x.tar.gz -L | tar -C ~/.terminus/plugins -xvz + terminus plugin:install terminus-secrets-manager-plugin ``` ## Create a Machine User in Pivotal Tracker @@ -52,45 +52,11 @@ As a best practice, start by creating a new machine user in Tracker. This user i ## Prepare your site: Securely Store User Credentials on Pantheon -Next, we need to provide Pantheon with the credentials for our new machine user in Pivotal Tracker. We'll securely store these values in the [private path](/guides/secure-development/private-paths#private-path-for-files) of Pantheon's filesystem. -We use the filesystem private path in this section because we don't want to track sensitive data like passwords in the codebase with git. - -1. First, let's check for existing secrets using Terminus (replace ``): - - ```bash{promptUser: user} - SITE= - terminus secrets:list $SITE.dev - ``` - - If no existing keys are found, run the following to create a new `secrets.json` file and upload it to Pantheon: - - ```bash{outputLines: 2} - echo '{}' > secrets.json - `terminus connection:info $SITE.dev --field=sftp_command` - ``` - - If the `files/private` directory doesn't exist, create it: - - ```bash{promptUser: user} - mkdir files/private - ``` - - Put the secrets file into the `private` directory: - - ```bash{outputLines: 1-3} - sftp> cd files/private - sftp> put secrets.json - sftp> bye - rm secrets.json - ``` - - Otherwise, continue to the next step. - -2. Use Terminus to write your Pivotal Tracker URL value in the private `secrets.json` file (replace ``): +2. Use Terminus to store your Pivotal Tracker URL value in Pantheon Secrets (replace ``): ```bash{promptUser: user} - terminus secrets:set $SITE.dev tracker_token + terminus secrets:site:set $SITE.dev tracker_token ``` diff --git a/source/images/guides/secrets/add-key.png b/source/images/guides/secrets/add-key.png new file mode 100644 index 0000000000..bac5f812d4 Binary files /dev/null and b/source/images/guides/secrets/add-key.png differ diff --git a/source/images/guides/secrets/secrets-relationships.png b/source/images/guides/secrets/secrets-relationships.png new file mode 100644 index 0000000000..3b1f6f4e31 Binary files /dev/null and b/source/images/guides/secrets/secrets-relationships.png differ diff --git a/source/images/guides/secrets/sendgrid-config.png b/source/images/guides/secrets/sendgrid-config.png new file mode 100644 index 0000000000..9691bf4cd8 Binary files /dev/null and b/source/images/guides/secrets/sendgrid-config.png differ diff --git a/source/images/guides/secrets/sendgrid-email-test.png b/source/images/guides/secrets/sendgrid-email-test.png new file mode 100644 index 0000000000..0bfa67c067 Binary files /dev/null and b/source/images/guides/secrets/sendgrid-email-test.png differ diff --git a/source/images/guides/secrets/sync-keys.png b/source/images/guides/secrets/sync-keys.png new file mode 100644 index 0000000000..c8398fbde4 Binary files /dev/null and b/source/images/guides/secrets/sync-keys.png differ diff --git a/source/releasenotes/2024-08-22-pantheon-secrets-limited-availability.md b/source/releasenotes/2024-08-22-pantheon-secrets-limited-availability.md new file mode 100644 index 0000000000..f1b20391e8 --- /dev/null +++ b/source/releasenotes/2024-08-22-pantheon-secrets-limited-availability.md @@ -0,0 +1,23 @@ +--- +title: Pantheon Secrets released for Limited Availability +published_date: "2024-08-22" +categories: [new-feature, tools-apis, security, documentation] +--- +Previously available only to Early Access participants, the Pantheon Secrets program is now released for Limited Availability, giving everyone access to this feature at no additional cost. + +## Highlights + +* **Secure**: Secrets are encrypted at rest and securely hosted on Pantheon. +* **Easy to use**: Create and update secrets via Terminus. +* **Governable**: Secrets can be set at organization level and shared with all the sites owned by that organization. +* **Overridable**: Secrets can be overridden at environment level when needed. + +## Documentation +Learn more about this new feature by exploring our new Pantheon Secrets Guide: + * [Introduction](/guides/secrets) + * [Secrets Overview](/guides/secrets/overview) + * [PHP Usage](/guides/secrets/php) + * [Drupal Key Usage](/guides/secrets/drupal) + * [Integrated Composer Usage](/guides/secrets/composer) + * [Local Development Usage](/guides/secrets/local) + * [Troubleshooting](/guides/secrets/troubleshooting)