GoCD secrets plugin that provides multi-tenant secrets.
It allows generating GoCD secrets that are bound to a tenant. A bound secret cannot be decrypted by any other tenant using the same GoCD instance. This prevents someone with access to other pipeline configs (especially in the pipeline-as-code context) from copying the secret and making GoCD decrypt it in their own pipeline.
- Download the latest version of the plugin from the releases page
- Install it on the GoCD server as described in the GoCD Plugin User Guide.
For users to generate secrets, there is a webservice that provides a UI and a REST endpoint.
The webservice can be run as a docker container. It is meant to be deployed on the same host as the GoCD server, for access to its encryption key.
docker run -d -p 1717:1717 -v /path/to/gocd/cipher.aes:/config/cipher.aes:ro ghcr.io/adnovum/tenantsecrets:latest
It provides the following entrypoints:
See "Generating secrets" on how to use these entrypoints.
Note: The webservice only provides a HTTP endpoint. You're encouraged to use the same HTTPS termination as for the GoCD server (e.g. nginx).
The following environment variables can be used to configure the webservice:
Env. variable | Default | Description |
---|---|---|
TENANTSECRETS_CIPHERFILE |
/config/cipher.aes |
Path to cipher file for secret encryption. |
TENANTSECRETS_DOCLINK |
https://github.com/adnovum/tenantsecrets |
The documentation link shown after encrypting a secret in the UI. |
GoCD admins have to create a secret configuration for each tenant that wishes to use tenant secrets:
- Id: The identifier of the secret configuration, which will be used by pipelines. It is recommended that you set it to the same value as the tenant identifier, because the plugin will not know about this ID, so it is error prone if the two are not aligned.
- Tenant identifier: The unique identifier of the tenant to which the secrets will be bound. The plugin will use this ID during secret generation and lookups.
- Cipher file: Path to the master key for the encryption. Defaults to
/godata/config/cipher.aes
, which is the cipher file used by the gocd-server docker image. To generate one, you can use e.g., commandopenssl rand -hex 16
. - Rules: Make sure to restrict the secret config to the pipeline group or environment that only the tenant has access to.
The security of tenant secrets relies on properly configured authorization. Each tenant should have an
exclusive pipeline group or environment assigned to them.
Otherwise an adversary can just place his pipeline into another tenant's pipeline group or environment and read the secrets bound
to that tenant.
- For pipelines configured via UI: users should not be allowed to create their own pipelines in arbitrary pipeline groups or environments.
- For pipeline-as-code configuration: Make sure to restrict config repos to specific pipeline groups and/or environments.
Once the webservice has been installed (see above), visit http://localhost:1717/secrets
and
follow the instructions in the form.
POST your secret to http://localhost:1717/secrets/api/<tenant identifier>
.
Example curl call:
curl 'http://localhost:1717/secrets/api/tenant1' -s -H 'Content-Type: text/plain' -d "my secret"
The secret can be referenced in pipelines using the secret param syntax.
{{SECRET:[tenant1][AES:YZEax9ra1bkL6Td9:5dgUOEIZACwfZGcZoRu5]}}
For example in a YAML configuration:
pipelines:
mypipeline:
environment_variables:
LE_SECRET: "{{SECRET:[tenant1][AES:YZEax9ra1bkL6Td9:5dgUOEIZACwfZGcZoRu5]}}"
Build and run unit tests:
./gradlew build
To run the webservice locally in the IDE, you need to declare a cipher file. Easiest is to do so
in an webservice/src/main/resources/application-default.yaml
file, which is never committed:
tenantsecrets:
cipherFile: /local/path/to/cipher.aes
Build docker image:
./gradlew bootBuildImage
Trigger a release on GitHub:
- Bump the
baseVersion
inbuild.gradle
- Push a release tag to trigger the release CI:
./gradlew release
This project uses default IntelliJ IDEA code style settings, with overrides from EditorConfig.