Skip to Content
CLI & DevOpsDevOps Guide

DevOps Guide

Automate certificate pin management in production environments using the TrustPin CLI. This guide covers the complete workflow for managing certificate pins from installation to automated CI/CD deployments.

Overview

TrustPin uses a two-step process for certificate pin updates:

  1. Upsert: Add or update certificate pins in your project configuration
  2. Sign: Cryptographically sign the configuration and publish it to the CDN

This separation allows you to:

  • Stage multiple pin changes before publishing
  • Review configuration changes before they go live
  • Maintain an audit trail of all pin modifications
  • Use different security controls for staging vs. publishing

Quick Start

1. Install the CLI

Homebrew (Recommended):

brew tap trustpin-cloud/trustpin-cli brew install trustpin-cli

Direct Download (Linux x64 for CI/CD):

curl -L https://github.com/trustpin-cloud/cloud-console-cli/releases/latest/download/trustpin-cli-linux-x64 -o trustpin-cli chmod +x trustpin-cli sudo mv trustpin-cli /usr/local/bin/

See Installation for platform-specific instructions.

2. Configure Authentication

Set the TRUSTPIN_API_TOKEN environment variable:

export TRUSTPIN_API_TOKEN="tp_your_token_here"

Get your Personal Access Token from TrustPin Console .

The CLI automatically uses this environment variable when available.

3. Get Your Project IDs

# List all projects trustpin-cli projects list # Get IDs in JSON format trustpin-cli projects list --output json | jq -r '.data.projects[] | "\(.organization_id) \(.id) \(.name)"'

Note your Organization ID and Project ID for subsequent commands.


Certificate Pin Management Workflow

Step 1: Extract Pin from Certificate

Extract the SPKI SHA-256 fingerprint and expiration date from your certificate:

#!/bin/bash CERT_FILE="cert.pem" # Extract SPKI SHA-256 (recommended - survives certificate renewal with same key) SPKI_SHA256=$(openssl x509 -in "$CERT_FILE" -pubkey -noout | \ openssl pkey -pubin -outform der | \ openssl dgst -sha256 -binary | \ base64) # Extract expiration date EXPIRES=$(openssl x509 -in "$CERT_FILE" -noout -enddate | \ cut -d= -f2 | \ xargs -I{} date -d "{}" -u +%Y-%m-%dT%H:%M:%SZ) echo "SPKI SHA-256: $SPKI_SHA256" echo "Expires: $EXPIRES"

Example output:

SPKI SHA-256: oxVSdCLgthL3M5Vnnzepq8WWlkUfRPYkpjLpm+wn+1o= Expires: 2026-04-13T08:37:02Z

Step 2: Upsert the Pin

Add or update the certificate pin in your project configuration:

trustpin-cli projects upsert \ <organization-id> \ <project-id> \ --domain api.example.com \ --pin spki-sha256:$SPKI_SHA256 \ --expires $EXPIRES \ --output json

Example output:

{ "status": "success", "operation": "upsert", "domain": "api.example.com", "action": "added", "pin": { "type": "spki-sha256", "value": "oxVSdCLgthL3M5Vnnzepq8WWlkUfRPYkpjLpm+wn+1o=", "expires_at": "2026-04-13T08:37:02Z" }, "config_version": { "before": 2, "after": 3 } }

Note: The configuration version increments, but changes are not yet published.

Step 3: Sign and Publish

Sign the configuration and publish it to the CDN:

Cloud-Managed Keys:

trustpin-cli projects sign \ <organization-id> \ <project-id> \ --password <master-password>

Bring Your Own Key (BYOK):

trustpin-cli projects sign \ <organization-id> \ <project-id> \ --private-key path/to/private-key.pem

Example output:

[1/5] Getting project information Project: Production API (Managed CDN with Cloud Keys) [2/5] Loading project configuration Configuration loaded with 3 domains [3/5] Preparing private key Using cloud-managed private key [4/5] Creating and signing JWT JWT signed successfully [5/5] Uploading signed configuration ✅ Configuration published successfully!

The signed configuration is now live and available to your mobile apps.


Complete Workflow Script

This script automates the entire process with error handling:

#!/bin/bash set -e ORG_ID="fb52418e-b5ae-4bff-b973-6da9ae07ba00" PROJECT_ID="9caaea0a-013e-4e7b-80ea-cee6bfb52b36" DOMAIN="api.example.com" CERT_FILE="certs/api-cert.pem" echo "═══ Step 1: Extract Pin from Certificate ═══" SPKI_SHA256=$(openssl x509 -in "$CERT_FILE" -pubkey -noout | \ openssl pkey -pubin -outform der | \ openssl dgst -sha256 -binary | \ base64) EXPIRES=$(openssl x509 -in "$CERT_FILE" -noout -enddate | \ cut -d= -f2 | \ xargs -I{} date -d "{}" -u +%Y-%m-%dT%H:%M:%SZ) echo " SPKI SHA-256: $SPKI_SHA256" echo " Expires: $EXPIRES" echo "" echo "═══ Step 2: Upsert Certificate Pin ═══" RESULT=$(trustpin-cli projects upsert "$ORG_ID" "$PROJECT_ID" \ --domain "$DOMAIN" \ --pin "spki-sha256:$SPKI_SHA256" \ --expires "$EXPIRES" \ --output json) echo "$RESULT" | jq '.' # Verify success STATUS=$(echo "$RESULT" | jq -r '.status') if [ "$STATUS" != "success" ]; then echo "❌ Failed to upsert pin" exit 1 fi ACTION=$(echo "$RESULT" | jq -r '.action') echo "✅ Pin ${ACTION} successfully" echo "" echo "═══ Step 3: Sign and Publish Configuration ═══" trustpin-cli projects sign "$ORG_ID" "$PROJECT_ID" \ --password "$MASTER_PASSWORD" echo "" echo "✅ Certificate pin updated and published!"

Advanced Use Cases

Verifying Published Configuration

After signing and publishing, verify the configuration is correctly deployed to the CDN:

# Verify JWS signature using public key from CDN trustpin-cli projects jws $ORG_ID $PROJECT_ID --verify # Decode and inspect published configuration trustpin-cli projects jws $ORG_ID $PROJECT_ID --decode # Save published JWS for archival/compliance trustpin-cli projects jws $ORG_ID $PROJECT_ID \ --output-file "archive/config-$(date +%Y%m%d-%H%M%S).jws"

Why validation matters:

  • Confirms the sign command successfully published to CDN
  • Catches CDN propagation delays or failures
  • Provides audit trail of published configurations
  • Enables comparison between database and CDN state

Example validation script:

#!/bin/bash set -e ORG_ID="fb52418e-b5ae-4bff-b973-6da9ae07ba00" PROJECT_ID="9caaea0a-013e-4e7b-80ea-cee6bfb52b36" echo "Verifying published configuration..." # Check if JWS is published JWS=$(trustpin-cli projects jws $ORG_ID $PROJECT_ID 2>/dev/null) if [ -z "$JWS" ]; then echo "❌ No JWS published on CDN" exit 1 fi # Verify signature if ! trustpin-cli projects jws $ORG_ID $PROJECT_ID --verify &>/dev/null; then echo "❌ JWS signature verification failed" exit 5 fi echo "✅ JWS signature valid" # Check version alignment trustpin-cli projects jws $ORG_ID $PROJECT_ID --decode | grep -E "(Current DB Version|Published Version)" echo "✅ Published configuration validated"

Self-Hosted CDN Deployment

For organizations hosting JWS configurations on their own infrastructure:

Workflow:

  1. Use TrustPin to manage and sign configurations (upsert + sign)
  2. Download the signed JWS from TrustPin CDN
  3. Deploy to your own CDN/servers
  4. Configure mobile SDKs to fetch from your infrastructure

Deployment script:

#!/bin/bash set -e ORG_ID="fb52418e-b5ae-4bff-b973-6da9ae07ba00" PROJECT_ID="9caaea0a-013e-4e7b-80ea-cee6bfb52b36" CDN_PATH="/var/www/cdn/trustpin" echo "═══ Step 1: Upsert Certificate Pins ═══" # Update your pins... trustpin-cli projects upsert $ORG_ID $PROJECT_ID \ --domain api.example.com \ --pin spki-sha256:$SPKI_SHA256 \ --expires $EXPIRES echo "" echo "═══ Step 2: Sign Configuration ═══" trustpin-cli projects sign $ORG_ID $PROJECT_ID \ --password "$MASTER_PASSWORD" echo "" echo "═══ Step 3: Download Signed JWS ═══" trustpin-cli projects jws $ORG_ID $PROJECT_ID \ --output-file "$CDN_PATH/config.jws" echo "" echo "═══ Step 4: Verify JWS Integrity ═══" if ! trustpin-cli projects jws $ORG_ID $PROJECT_ID --verify; then echo "❌ JWS verification failed - aborting deployment" exit 5 fi echo "" echo "═══ Step 5: Deploy to CDN ═══" # Example: Upload to S3, CloudFront, or your CDN aws s3 cp "$CDN_PATH/config.jws" s3://your-bucket/trustpin/config.jws \ --cache-control "public, max-age=3600" \ --metadata "version=$(date +%s)" # Invalidate CDN cache if needed aws cloudfront create-invalidation \ --distribution-id YOUR_DISTRIBUTION_ID \ --paths "/trustpin/config.jws" echo "✅ JWS deployed to self-hosted CDN"

Benefits:

  • Full control over CDN infrastructure and caching
  • Compliance with data residency requirements
  • Integration with existing CDN/monitoring systems
  • Custom cache invalidation strategies

Troubleshooting

Authentication Issues

Problem: HTTP 401 Unauthorized

Solutions:

# Verify token is set correctly echo $TRUSTPIN_API_TOKEN # Test authentication trustpin-cli projects list --output json # Reconfigure CLI trustpin-cli configure

In CI/CD:

  • Verify TRUSTPIN_API_TOKEN secret is set correctly
  • Ensure token hasn’t expired (create new token if needed)
  • Check token has access to the organization/project

Validation Errors

Problem: Invalid pin format or type

❌ Validation failed: invalid pin type: sha255 Valid types: sha256, sha512, spki-sha256, spki-sha512

Solution: Fix typo in pin type (e.g., sha255sha256)

Problem: Invalid base64 encoding

❌ Validation failed: invalid base64 encoding in pin value

Solution: Ensure hash is base64-encoded, not hex:

# Correct: base64 encoding openssl dgst -sha256 -binary | base64 # Incorrect: hex encoding openssl dgst -sha256

Problem: Wrong hash length

❌ Validation failed: invalid sha256 hash length: expected 32 bytes, got 16 bytes

Solution: Verify you’re hashing the correct data:

# For SPKI pins (correct) openssl x509 -in cert.pem -pubkey -noout | \ openssl pkey -pubin -outform der | \ openssl dgst -sha256 -binary | base64 # For certificate pins (correct) openssl x509 -in cert.pem -outform der | \ openssl dgst -sha256 -binary | base64

Private Key Issues (BYOK)

Problem: Failed to decrypt private key

❌ Failed to decrypt private key: cipher: message authentication failed

Solutions:

  • Verify master password is correct for cloud-managed keys
  • Verify private key password is correct for BYOK
  • Check private key file is in PEM format: file private-key.pem

Problem: Private key format errors in CI/CD

# Verify key is properly decoded file private-key.pem # Should show: "PEM RSA private key" or similar # Check file permissions ls -la private-key.pem # Should be 600 or 400

Network Issues

Problem: Connection timeout or network errors

Solutions:

# Test API connectivity curl -H "Authorization: Bearer $TRUSTPIN_API_TOKEN" \ https://api.trustpin.cloud/users # Check API base URL echo $TRUSTPIN_API_BASE_URL # Use verbose mode for debugging trustpin-cli projects sign <org-id> <project-id> --verbose

Upsert Operation Issues

Problem: Upsert succeeds but nothing changes

Reason: The pin already exists with the same expiration (idempotent operation)

Response:

{ "status": "success", "operation": "upsert", "action": "no_change", "message": "Pin already exists with same expiration" }

Solution: This is expected behavior. No action needed.

Exit Codes

The CLI uses standard exit codes for automation:

CodeMeaningExample
0Success or no-opPin added/updated, or already exists
2API error401, 404, 500 HTTP errors
4Validation errorInvalid domain, pin format, or type
99Unexpected errorNetwork timeout, file I/O error

Use in scripts:

if ! trustpin-cli projects upsert ... --output json > result.json; then EXIT_CODE=$? echo "❌ Upsert failed with exit code $EXIT_CODE" cat result.json exit $EXIT_CODE fi

Getting Help

View command help:

trustpin-cli --help trustpin-cli projects --help trustpin-cli projects upsert --help trustpin-cli projects sign --help

Enable verbose output:

trustpin-cli projects upsert ... --verbose trustpin-cli projects sign ... --verbose

Check CLI version:

trustpin-cli --version

For additional support, contact support@trustpin.cloud or visit the TrustPin Console .