This project integrates with BeyondTrust Password Safe and provides two core actions for secret management: get_secret and create_secret. The get_secret action is used to retrieve existing secrets, while the create_secret action allows the creation of new secrets. Detailed descriptions and usage examples for each action are provided in the following sections.
Warning
Breaking changes
Instead of a single unified operation for handling secrets, this release splits the functionality into two distinct operations:
- get_secret – Retrieves a secret from Secrets Safe
(BeyondTrust/secrets-safe-action/get_secret) - create_secret – Creates a secret in Secrets Safe
(BeyondTrust/secrets-safe-action/create_secret)
If you are upgrading from version 1.x, you must update your GitHub Actions workflows to use these new operation names.
Workflows that relied on the previous combined behavior will no longer work unless they are updated to use either get_secret or create_secret.
This action retrieves ASCII secrets from BeyondTrust Secrets Safe and makes them available in the GitHub action workflow. The secrets are requested using either a Secrets Safe path or a path to a managed account which is composed of a managed system and account. The action output returns the secrets with an ID specified in the action request. This allows immediate retrieval and usage of secrets from your BeyondTrust Secrets Safe instance. Retrieved secrets are masked on the GitHub runner used to retrieve the secret. This helps reduce the chance that secrets are printed or logged by accident.
Warning: It is important that security-minded engineers review workflow composition before changes are run with access to secrets.
The Secrets Safe action supports retrieval of secrets from BeyondInsight/Password Safe versions 23.1 or greater.
For this extension to retrieve a secret the Secrets Safe instance must be preconfigured with the secret in question and must be authorized to read it.
Runners must use a Linux operating system. Additionally, self-hosted runners will need Docker installed.
Optional: The API Key configured in BeyondInsight for your application. If not set, then client credentials must be provided.
Required: API OAuth Client ID.
Required: API OAuth Client Secret.
Required: BeyondTrust Password Safe API URL.
https://example.com:443/BeyondTrust/api/public/v3
Optional: The recommended version is 3.1. If no version is specified, the default API version 3.0 will be used
Required: Path of the secret to retrieve.
[
{
"path": "folder1/folder2/title",
"output_id": "title"
},
{
"path": "folder1/folder2/title2",
"output_id": "title2"
}
]Required: Path of the Managed account to retrieve.
[
{
"path": "system/account",
"output_id": "account"
},
{
"path": "system/account2",
"output_id": "account2"
}
]Content of the certificate (cert.pem) for use when authenticating with an API key using a Client Certificate.
Certificate private key (key.pem). For use when authenticating with an API key
Indicates whether to verify the certificate authority on the Secrets Safe instance. Defaults to true if not specified. Accepts true, false, or the path to a CA bundle inside the action container.
VERIFY_CA: true
Warning: false is insecure, instructs the Secrets Safe custom action not to verify the certificate authority.
true verifies against certifi's bundled roots, not the operating system trust store, so a private or internal CA has to be supplied as a bundle path. See TLS certificate verification (VERIFY_CA).
Level of logging verbosity. Default INFO.
Levels: CRITICAL, FATAL, ERROR, WARNING, WARN, INFO, DEBUG, NOTSET
Optional: When set to true, the decrypted password field is returned. When set to false, the password field is omitted. This option applies only to secret retrieval type. Defaults to true if not specified.
The action stores the retrieved secrets in output variables defined by the end user. The <output_id> must be a unique identifier within the outputs object. The <output_id> must start with a letter or _ and contain only alphanumeric characters, -, or _. See secret_path and managed_account_path.
uses: BeyondTrust/secrets-safe-action/get_secret@bd174328f6b88a6cd795049a9dbe2a81c8669342 # v2.0.0
env:
API_URL: ${{vars.API_URL}}
VERIFY_CA: ${{vars.VERIFY_CA}}
CLIENT_ID: ${{secrets.CLIENT_ID}}
CLIENT_SECRET: ${{secrets.CLIENT_SECRET}}
CERTIFICATE: ${{secrets.CERTIFICATE}}
CERTIFICATE_KEY: ${{secrets.CERTIFICATE_KEY}}
API_VERSION: ${{vars.API_VERSION}}
with:
SECRET_PATH: '{"path": "folder1/folder2/title", "output_id": "title"}'
MANAGED_ACCOUNT_PATH: '{"path": "system/account", "output_id": "account"}'This action creates new secrets in BeyondTrust Secrets Safe. The action supports creating different types of secrets including credentials (username/password), text secrets, and file-based secrets. Created secrets are stored in specified folders within your Secrets Safe instance.
The action supports two authentication methods:
- API Key Authentication: Using an API key with optional client certificates
- OAuth Client Credentials: Using client ID and client secret
- Appropriate permissions to create secrets in the target folder
- Target parent folder must exist in Secrets Safe
- Runners must use a Linux operating system with Docker installed
Optional: The API Key configured in BeyondInsight for your application. If not set, then client credentials must be provided.
Optional: The API OAuth Client ID configured in BeyondInsight for your application.
Optional: The API OAuth Client Secret configured in BeyondInsight for your application.
Required: The API URL for the Secrets Safe instance.
https://example.com:443/BeyondTrust/api/public/v3
Optional: The recommended version is 3.1. If no version is specified, the default API version 3.0 will be used.
Optional: Indicates whether to verify the certificate authority on the Secrets Safe instance. Defaults to true. Accepts true, false, or the path to a CA bundle inside the action container — true verifies against certifi's bundled roots, not the operating system trust store. See TLS certificate verification (VERIFY_CA).
Optional: Content of the certificate (cert.pem) for use when authenticating with an API key using a Client Certificate.
Optional: Certificate private key (key.pem) for use when authenticating with an API key using a Client Certificate.
Required: Title of the secret to be created. Must be unique within the parent folder.
Required: Name of the parent folder where the secret will be created. The folder must exist in Secrets Safe.
Optional: Description of the secret for documentation purposes.
Optional: Username for credential type secrets.
Optional: Password for credential type secrets.
Optional: Text content for text type secrets.
Optional: File content for file type secrets (base64 encoded or plain text).
Optional: File name for file type secrets.
Optional: ID of the owner for the secret.
Optional: Type of the owner (User or Group).
Optional: List of owners for the secret in JSON format.
[{"user_id": 123, "owner_id": 123}]Optional: Password rule ID for credential secrets to enforce password policies.
Optional: Additional notes for the secret.
Optional: URLs associated with the secret in JSON format.
[{"url": "https://example.com"}]Optional: Level of logging verbosity. Default: INFO
Levels: CRITICAL, FATAL, ERROR, WARNING, WARN, INFO, DEBUG, NOTSET
- name: Create credential secret
id: credential_secret
uses: BeyondTrust/secrets-safe-action/create_secret@bd174328f6b88a6cd795049a9dbe2a81c8669342 # v2.0.0
env:
API_URL: ${{vars.API_URL}}
CLIENT_ID: ${{secrets.CLIENT_ID}}
CLIENT_SECRET: ${{secrets.CLIENT_SECRET}}
VERIFY_CA: ${{vars.VERIFY_CA}}
LOG_LEVEL: ${{vars.LOG_LEVEL}}
API_VERSION: "3.1"
with:
SECRET_TITLE: "Secret Title"
PARENT_FOLDER_NAME: "Parent folder name"
SECRET_DESCRIPTION: ""
USERNAME: "username"
PASSWORD: "p4ssw0rd!#"
TEXT: ""
FILE_NAME: ""
FILE_CONTENT: ""
OWNER_ID: "1"
OWNER_TYPE: "User"
NOTES: ""
OWNERS: '[{"owner_id": 1}]'- name: Create Text secret
id: text_secret
uses: BeyondTrust/secrets-safe-action/create_secret@bd174328f6b88a6cd795049a9dbe2a81c8669342 # v2.0.0
env:
API_URL: ${{vars.API_URL}}
CLIENT_ID: ${{secrets.CLIENT_ID}}
CLIENT_SECRET: ${{secrets.CLIENT_SECRET}}
VERIFY_CA: ${{vars.VERIFY_CA}}
LOG_LEVEL: ${{vars.LOG_LEVEL}}
API_VERSION: "3.1"
with:
SECRET_TITLE: "Secret Title"
PARENT_FOLDER_NAME: "Parent folder name"
SECRET_DESCRIPTION: ""
USERNAME: ""
PASSWORD: ""
TEXT: "Doc_S3guro!21"
FILE_NAME: ""
FILE_CONTENT: ""
OWNER_ID: "1"
OWNER_TYPE: "User"
NOTES: ""
OWNERS: '[{"owner_id": 1}]'- name: Create File secret
id: file_secret
uses: BeyondTrust/secrets-safe-action/create_secret@bd174328f6b88a6cd795049a9dbe2a81c8669342 # v2.0.0
env:
API_URL: ${{vars.API_URL}}
CLIENT_ID: ${{secrets.CLIENT_ID}}
CLIENT_SECRET: ${{secrets.CLIENT_SECRET}}
VERIFY_CA: ${{vars.VERIFY_CA}}
LOG_LEVEL: ${{vars.LOG_LEVEL}}
API_VERSION: "3.1"
with:
SECRET_TITLE: "Secret Title"
PARENT_FOLDER_NAME: "Parent folder name"
SECRET_DESCRIPTION: ""
USERNAME: ""
PASSWORD: ""
TEXT: ""
FILE_NAME: "secret.txt"
FILE_CONTENT: "Doc4!Pass789"
OWNER_ID: "1"
OWNER_TYPE: "User"
NOTES: ""
OWNERS: '[{"owner_id": 1}]'Both actions read the same VERIFY_CA environment variable, which accepts three kinds of value:
| Value | Behavior |
|---|---|
true (default), 1, yes, on, enable, enabled |
Verify against the CA store the requests library defaults to — the roots bundled with certifi. |
false, 0, no, off, disable, disabled |
Insecure. Skip certificate verification entirely. |
A path to an existing file or directory, e.g. /github/workspace/ca/ca-bundle.crt |
Verify against that CA bundle. |
Values are case-insensitive and surrounding whitespace is ignored. Anything else — including a mistyped or missing bundle path — fails the step at startup with an EnvironmentError rather than silently falling back to true and failing to trust the CA you asked for.
true is not the operating system trust store. requests verifies against certifi's bundled Mozilla root certificates, not OpenSSL's default paths, so true and /etc/pki/tls/certs/ca-bundle.crt are different trust stores and can behave differently. Anything an administrator added to a host's OS store with update-ca-trust / update-ca-certificates — an internal PKI or a self-signed Password Safe certificate — is invisible to certifi. If Password Safe presents a certificate that does not chain to a public root, VERIFY_CA: "true" fails with CERTIFICATE_VERIFY_FAILED and you must point VERIFY_CA at a bundle that contains your CA. Do not disable verification to work around this.
These are Docker container actions, so the bundle must exist inside the action container, which does not inherit the runner's trust store. The runner mounts the repository workspace at /github/workspace in the container, so a bundle that is checked in — or written by an earlier step — is reachable under that path:
- uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1
- name: Get secret
uses: BeyondTrust/secrets-safe-action/get_secret@bd174328f6b88a6cd795049a9dbe2a81c8669342 # v2.0.0
env:
API_URL: ${{vars.API_URL}}
CLIENT_ID: ${{secrets.CLIENT_ID}}
CLIENT_SECRET: ${{secrets.CLIENT_SECRET}}
# Path inside the container, not on the runner.
VERIFY_CA: "/github/workspace/ca/ca-bundle.crt"
with:
SECRET_PATH: '{"path": "folder1/folder2/title", "output_id": "title"}'To keep the bundle out of the repository, write it from a secret in a preceding step:
- name: Write CA bundle
run: |
mkdir -p "$GITHUB_WORKSPACE/ca"
printf '%s\n' "${{ secrets.CA_BUNDLE }}" > "$GITHUB_WORKSPACE/ca/ca-bundle.crt"Use the literal /github/workspace/... path for VERIFY_CA: ${{ github.workspace }} expands to the path on the runner (for example /home/runner/work/repo/repo), which does not exist inside the container.
As an alternative that needs no change to VERIFY_CA, requests also honors the standard REQUESTS_CA_BUNDLE (or CURL_CA_BUNDLE) environment variable whenever verification is enabled; set it on the step's env with the same in-container path. Note that SSL_CERT_FILE has no effect on requests.
The action logs which trust store is in effect at INFO level, which is the quickest way to confirm the bundle was picked up:
Verifying certificates against CA bundle: /github/workspace/ca/ca-bundle.crt
Download the pfx certificate from Secrets Safe and extract the certificate and the key to be pasted into a GitHub secret.
openssl pkcs12 -in client_certificate.pfx -nocerts -out ps_key.pem -nodes
openssl pkcs12 -in client_certificate.pfx -clcerts -nokeys -out ps_cert.pem
Copy the text from the ps_key.pem to a secret.
-----BEGIN PRIVATE KEY-----
...
-----END PRIVATE KEY-----
Copy the text from the ps_cert.pem to a secret.
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
- Contact BeyondTrust support