Configure Jenkins AWS Secrets Manager Credentials Provider Plugin to Work with Moto Standalone Server

The AWS Secrets Manager Credentials Provider Plugin (SM Plugin) for Jenkins provides an option for specifying a custom service endpoint address. This allows SecretsManager credentials to be sourced from mock AWS services, such as Moto server.

This post describes the process of creating a Jenkins/Moto docker compose stack with instructions on how to go about configuring the SM plugin to use Moto.

Local Jenkins/Moto Server Stack using Docker Compose

The following docker-compose.yml sample provisions a Jenkins/Moto stack.

version: '3.8'

services:

  motoserver:
    image: motoserver/moto:latest
    container_name: motoserver   
    ports:
      - 5000:5000
    environment:
      - MOTO_PORT=5000

  jenkins_master:
    image: jenkins/jenkins:lts-jdk11
    user: jenkins
    container_name: jenkins_master                
    volumes:
      - jenkins_home:/var/jenkins_home            
    ports:
      - 8080:8080

volumes:
  jenkins_home:
    name: jenkins_home

Once the stack is launched, it provides two networked containers with internal addresses:

jenkins_master:8080
motoserver:5000

Bring up the stack:

$ docker compose up -d

Complete the Jenkins installation process by visiting http://localhost:8080. To keep the containers “lightweight”, installation of plugins was skipped during the setup process.

Install Required Plugins

AWS Secrets Manager Credentials Provider

  • Install the SM provider plugin by navigating to:
    Dashboard -> Manage Jenkins -> Plugins -> Available Plugins:
Install Secretsmanager Credentials Provider Plugin

Pipeline: Declarative

In addition to the SM Plugin, the Pipeline:Declarative will also be installed to allow for creation of a test pipeline.

Install Pipeline Declarative

Once both plugins are installed, restart the jenkins_master service by running:

$ docker compose restart jenkins_master

[+] Restarting 1/1
✔ Container jenkins_master  Started

Configure SM Plugin to use Moto Endpoint

To configure the SM provider plugin, navigate to Dashboard -> Manage Jenkins -> System.

  • Scroll down to the section AWS Secrets Manager Credentials Provider and enter the following details:
CacheEnabled
Credentials ProviderStatic
AWS Access Keytesting
AWS Secret Keytesting
Service Endpointhttp://motoserver:5000
Signing RegionUS East (N.Virginia)
  • Save changes

Creating a Secret

For testing, we’ll store a GitHub API Key with a name git-api-key, and value myapisecret using our Moto mock server.

After carefully reading the plugin guidelines for creating and tagging secrets, create the secret.

$ aws --endpoint-url http://localhost:5000 
                      --region us-east-1 secretsmanager create-secret 
                      --name 'git-api-key' 
                      --secret-string 'myapisecret' 
                      --tags 'Key=jenkins:credentials:type,Value=string' 
                      --description 'API token'

Output:

{
    "ARN": "arn:aws:secretsmanager:us-east-1:123456789012:secret:git-api-key-HYBogf",
    "Name": "git-api-key",
    "VersionId": "9491472c-bbd6-4387-89d9-2c9a2d36f758"
}

The secret should automatically appear at:
Dashboard -> Manage Jenkins -> Credentials.

Note: With credential caching enabled for the plugin, it can take a few minutes before the secret is visible within Jenkins.

Accessing the Secret from a Pipeline

  • Create a test pipeline with name: secrets-manager-plugin-test
  • Use the following pipeline script to access and display the secret to ensure its contents are as expected
pipeline {
    agent any
    stages {
        stage('Fetch Secret - Moto Endpoint') {
            environment {
                AWS_REGION="us-east-1"
            }
            steps {
                script {
                    withCredentials([string(credentialsId: 'git-api-key', variable: 'GIT_API_KEY')]) {
                        print 'GIT_API_KEY=' + "${GIT_API_KEY}"
                        def charArray = GIT_API_KEY.toCharArray()
                        def passwd = ""
                        for (c in charArray) {
                            passwd += " "+c.toString()
                        }
                        println "the password is"+passwd
                        println "the password is"+passwd.replaceAll(" ", "")
                    }
                }
            }
        }
    }
}
  • To circumvent the protection mechanism (masking) implemented by plugin(s), an iterator and Groovy’ toCharArray() is used
  • Save the pipeline and run a test build
  • Check build output log