This article is written by Himesh Panchal
Secret management in shared environments like Continuous Integration and Delivery services is challenging. It’s essential to keep secrets secure and ensure they don’t end up in the wrong place, like logs or code repositories.
Integrating solutions like 1Password into CI/CD workflows offer the advantage of centralising secret management, and it also allows you to encrypt every secret, providing controlled programmatic access to applications.
In this guide, we’ll explore how to make the most of 1Password Service Accounts within your CI/CD pipelines.
Creating a Service Account in 1Password
Service accounts provide a way to interact with 1Password without using individual user credentials, making it ideal for automated processes.
-
Log in to 1Password’s web interface.
-
Navigate to the
Integrations
section. Click onother
option.
- Click
Create New Service Account
and give it a name, e.g. codemagic.
- Select the vault(s) you want to grant access to for this service account.
-
After creating the service account, an authentication token will be auto-generated. Save the auth token to 1Password.
-
Copy the auth token. Here, we will use Codemagic CI/CD for demonstration purposes, but the same process should work with any CI/CD service.
Adding auth token to Codemagic
- Open your Codemagic app > Teams > settings >
codemagic.yaml
settings, and go to the Global variables and secrets tab. - Enter the Variable name,
OP_SERVICE_ACCOUNT_TOKEN
. - Paste the token as a Variable value.
- Enter the variable group name, e.g. 1password. Click the button to create the group.
- Make sure the Secure option is selected.
- Click the Add button to add the variable.
- Now, we can use this token to retrieve secrets from the 1Password vault.
Configuring 1Password in codemagic.yaml
Installing 1Password CLI using Homebrew
name: Installing 1Password CLI
script: brew install 1password-cli
Verifying the Authenticated User/Service Account in 1Password
name: Verifying the Authenticated User
script: op user get --me
op user get --me
This command fetches and displays details of the currently authenticated user or service account in the 1Password CLI. The –me flag gets the authenticated user’s details.
Reading secret references with op read
Fetch the login & API credentials
The command uses curl
to make a POST request to BrowserStack’s API to upload an iOS app IPA file for automated testing. It securely retrieves the username and auth token for BrowserStack from 1Password using the op read
command and then uses them for authentication in the request.
name: Upload artifact to Browserstack for Testing
script: |
curl -u "$(op read op://ci/browserstack/username):$(op read op://ci/browserstack/password)" \
-X POST "https://api-cloud.browserstack.com/app-live/upload" \
-F "file=@build/ios/ipa/your_app_release.ipa"
Fetch the document file contents
In this step, we’re fetching the firebase
document from a 1Password vault named ci
and storing it in firebase.json
file.
name: store firebase credentials
script: op read -o ./firebase_creds.json op://ci/serviceAccount/firebase.json
op read
Read a secret by secret references.- o, –out-file string, Write the secret to a file instead of stdout.
<reference>
reference of the secret path stored in theci
vault.
Reading secret references with op run
You can map environment variables to specific secret references. By utilizing op run
, these secrets can be dynamically passed to applications or scripts when they’re executed.
The op run
command checks the environment variables for any references to secrets, fetches the relevant values from 1Password, and then initiates the specified command in a subprocess.
During this subprocess’s lifecycle, the secrets are accessible as environment variables, ensuring they’re available only when needed and safeguarded afterwards.
Consider the below example: ci.env
file, which has the 1Password secret reference
. You can check into source control and use the same environment everywhere.
keyStorePass="op://ci/keystore/password"
keyAlias="op://ci/keystore/alias"
keyPass="op://ci/keystore/keypass"
Code signing Android Application using gradle
In the below script op run command, combined with the –env-file="./ci.env" option,
- Loads Environment Variables: It reads the
ci.env
file and loads the environment variables specified within. - Resolves Secret References: If any of the environment variables have values starting with
op://
,op run
recognizes them as references to secrets within 1Password. It fetches the actual secret values corresponding to those references. - Runs the Command in a Subprocess: It then runs the specified command (in this case,
./gradlew bundleRelease
) in a subprocess where the environment variables are set to the resolved secret values. - Cleans Up: Once the subprocess finishes, the environment variables (with secrets) are cleaned up. They aren’t persisted or exposed beyond the lifecycle of the subprocess.
name: Sign Android App
script: op run --env-file="./ci.env" -- ./gradlew bundleRelease
By dynamically providing these critical credentials, developers ensure the app’s integrity while keeping sensitive information away from static build configurations.
Summary
Incorporating 1Password into your CI/CD processes adds another layer of security, centralising and streamlining the management of secrets and credentials. By centralising and securely managing secrets, you reduce risks associated with manual secret management.