How do I create jenkins credentials using a golang script?
In this blog article, we are going use GoJenkins library to create jenkins Username, String and SSH credentials.
The Jenkins credentials plugin provides a default internal credentials store, which can be used to store high value or privileged credentials, such as Amazon bucket deployment username/password combinations and GitHub user tokens.
The jenkins credentials binding plugin – https://plugins.jenkins.io/credentials-binding – Allows credentials to be bound to environment variables for use from miscellaneous build steps.
Prerequisites
To follow along, ensure:
- you have a working jenkins with admin username and password
- You have golang set up in your local machine
- You know basics of golang and Jenkins
Table of content
- Install the Credential and Credential Binding Plugin
- Create directory structure and initialize module
- Adding imports
1. Install the Credential and Credential Binding Plugin
Go to Jenkins > Plugins Manager and select Credentials and Credential Bindings Plugin. Then click install.
1. Create directory structure and initialize module
Create a directory.
mkdir jenkins-credentials
Switch to the directory, Initialize a module in that directory using the go mod init
command:
➜ go mod init jenkins-credentials
go: creating new go.mod: module jenkins-credentials
go: to add module requirements and sums:
go mod tidy
2. Adding imports
We need to instantiate the package and add imports. Let’s do it with this code block:
package main
import (
"context"
"log"
"github.com/bndr/gojenkins"
)
In the above code snippet, the most important import is the gojenkins one – github.com/bndr/gojenkins
. This is the module that we will use manage jenkins credentials.
2. Define constants
The next bit is to define constants. We need these to instantiate things like jenkins url, username and password that do not change. These will be used in the script.
Define the constants:
const (
jenkinsUrl = "https://jenkins.citizix.dev/"
jenkinsUser = "admin"
jenkinsPass = "Sup3rSecu4"
domain = "_"
scope = "GLOBAL"
)
3. Initialize connection to jenkins
Next is the main function. We need to connect to jenkins. We can also provide a CA certificate if server is using self-signed certificate. Checkout this code block:
ctx := context.Background()
jenkins := gojenkins.CreateJenkins(nil, jenkinsUrl, jenkinsUser, jenkinsPass)
// Provide CA certificate if server is using self-signed certificate
// caCert, _ := ioutil.ReadFile("/tmp/ca.crt")
// jenkins.Requester.CACert = caCert
_, err := jenkins.Init(ctx)
if err != nil {
log.Fatalf("Jenkins init failed: %v", err)
}
4. Define credentials structs
Next, for each credential that we are defining we need a struct. gojenkins already defines structs that we can just pass values.
Username credentials
These are credentials that have a key and a value. Let’s instantiate a struct that an be expanded:
usernameCreds := []*gojenkins.UsernameCredentials{
&gojenkins.UsernameCredentials{
ID: "app-one-mysql-credentials",
Description: "Username and Password Credentials used bu App one",
Scope: scope,
Username: "app_one_user",
Password: "Sup3rS3cret",
},
}
Use this block to create the credentials:
for i, cred := range usernameCreds {
log.Printf("Adding username cred %v: %v to %v", i, cred.ID, jenkinsUrl)
err = cm.Add(ctx, domain, cred)
if err != nil {
log.Fatalf("failed to add username credential =[%v]: %v", err, cred.ID)
}
}
String credentials
These are strings that are credentials. Let us define with:
secretCreds := []*gojenkins.StringCredentials{
&gojenkins.StringCredentials{
ID: "dev-appone-postgres-url",
Description: "Dev appone postgres url",
Scope: scope,
Secret: "postgres://dev_appone:SuperSecret@192.168.10.20:5432/dev_appone?sslmode=disable",
},
}
Now create:
for i, cred := range secretCreds {
log.Printf("Adding secret cred %v: %v to %v", i, cred.ID, jenkinsUrl)
err = cm.Add(ctx, domain, cred)
if err != nil {
log.Fatalf("failed to add secret credential =[%v]: %v", err, cred.ID)
}
}
SSH credentials
This is private ssh key creds. To define, use this snippet:
sshCreds := []*gojenkins.SSHCredentials{
&gojenkins.SSHCredentials{
ID: "citizix-ssh-key",
Description: "Citizix proivate ssh key",
Scope: scope,
Username: "spay",
PrivateKeySource: "~/.ssh/id_citizix",
},
}
Now let’s create:
for i, cred := range sshCreds {
log.Printf("Adding ssh cred %v: %v to %v", i, cred.ID, jenkinsUrl)
err = cm.Add(ctx, domain, cred)
if err != nil {
log.Fatalf("failed to add ssh credential =[%v]: %v", err, cred.ID)
}
}
Getting a list of existing credentials
To get all the credentials, use this:
existingCreds, err := cm.List(ctx, domain)
if err != nil {
log.Fatalf("could not get creds: %v", err)
}
log.Printf("existing credentials: %+v", existingCreds)
5. Whole code
This is the whole code:
package main
import (
"context"
"log"
"github.com/bndr/gojenkins"
)
const (
jenkinsUrl = "https://jenkins.citizix.dev/"
jenkinsUser = "admin"
jenkinsPass = "Sup3rSecu4"
domain = "_"
scope = "GLOBAL"
)
func main() {
ctx := context.Background()
jenkins := gojenkins.CreateJenkins(nil, jenkinsUrl, jenkinsUser, jenkinsPass)
// Provide CA certificate if server is using self-signed certificate
// caCert, _ := ioutil.ReadFile("/tmp/ca.crt")
// jenkins.Requester.CACert = caCert
_, err := jenkins.Init(ctx)
if err != nil {
log.Fatalf("Jenkins init failed: %v", err)
}
cm := gojenkins.CredentialsManager{J: jenkins}
usernameCreds := []*gojenkins.UsernameCredentials{
&gojenkins.UsernameCredentials{
ID: "app-one-mysql-credentials",
Description: "Username and Password Credentials used bu App one",
Scope: scope,
Username: "app_one_user",
Password: "Sup3rS3cret",
},
}
sshCreds := []*gojenkins.SSHCredentials{
&gojenkins.SSHCredentials{
ID: "citizix-ssh-key",
Description: "Citizix proivate ssh key",
Scope: scope,
Username: "spay",
PrivateKeySource: "~/.ssh/id_citizix",
},
}
secretCreds := []*gojenkins.StringCredentials{
&gojenkins.StringCredentials{
ID: "dev-appone-postgres-url",
Description: "Dev appone postgres url",
Scope: scope,
Secret: "postgres://dev_appone:SuperSecret@192.168.10.20:5432/dev_appone?sslmode=disable",
},
}
for i, cred := range usernameCreds {
log.Printf("Adding username cred %v: %v to %v", i, cred.ID, jenkinsUrl)
err = cm.Add(ctx, domain, cred)
if err != nil {
log.Fatalf("failed to add username credential =[%v]: %v", err, cred.ID)
}
}
for i, cred := range secretCreds {
log.Printf("Adding secret cred %v: %v to %v", i, cred.ID, jenkinsUrl)
err = cm.Add(ctx, domain, cred)
if err != nil {
log.Fatalf("failed to add secret credential =[%v]: %v", err, cred.ID)
}
}
for i, cred := range sshCreds {
log.Printf("Adding ssh cred %v: %v to %v", i, cred.ID, jenkinsUrl)
err = cm.Add(ctx, domain, cred)
if err != nil {
log.Fatalf("failed to add ssh credential =[%v]: %v", err, cred.ID)
}
}
// Bonus, to get a list of added credentials use this:
existingCreds, err := cm.List(ctx, domain)
if err != nil {
log.Fatalf("could not get creds: %v", err)
}
log.Printf("existing credentials: %+v", existingCreds)
}
Building and testing the script
Go mod tidy:
➜ go mod tidy
go: finding module for package github.com/bndr/gojenkins
go: found github.com/bndr/gojenkins in github.com/bndr/gojenkins v1.1.0
Build:
➜ go build -o jenkins-creds
Test Execution:
➜ ./jenkins-creds
2021/10/07 22:04:58 creds: [github-token docker-registry aws-iac-access spay-ssh-key spay-mssql-sa-pw]
2021/10/07 22:04:58 Adding username cred 0: app-one-mysql-credentials to http://jenkins.citizix.com/
2021/10/07 22:05:00 Adding secret cred 0: dev-appone-postgres-url to http://jenkins.citizix.com/
2021/10/07 22:05:01 Adding ssh cred 0: citizix-ssh-key to http://jenkins.citizix.com/
Conclusion
We managed to automate the process of creating jenkins credentials.