Finally, the meat of the action.
We have:
- Code in a repo
- Secrets that we need to keep secret
- An SBOM to generate
- Code and binaries to verify
From last year's talk:
- Install Jenkins
- Install Dependency-Check (for SCA)
- Install SonarQube (for SAST)
- Create the pipeline as code (for best results)
- Before, just grabbed a copy of the code
- What if we need to check it out?
1. Create asymmetric keypair
- ssh-keygen -b 4096
- cat ~/.ssh/id_rsa.pub
- Copy for next steps
2. Setup key in GitHub
- Settings
- SSH and GPG keys
- New SSH key button
- Name the key
- Type: Authentication key
- Paste copied public key
3. Setup key in Jenkins
- Go to the project > Configure page
- Scroll to Pipeline section > Repositories
- Under Credentials, Click +Add button and select Jenkins
- For Kind, select SSH Username with private key
- For Scope: Global
- For ID, enter a unique name for the key
- For Username: the login for your repo (optionally treat it as a secret)
- Copy the private key from a terminal using sudo cat ~/.ssh/id_rsa
- Paste the private key into Jenkins
- Enter the passphrase used when creating the keypair
- Click Add
- Back on the project's Configure page, select the credential just created
- Click Save
4. Configure Git host key verification in Jenkins
The console output of a build will show "You're using 'Known hosts file' strategy to verify ssh host keys, but your known_hosts file does not exist." We need to tell Jenkins how to identify the remote host it's connecting to.
- Run cat ~/.ssh/known_hosts in a terminal
- Copy the github.com key (to the end "=")
- Manage Jenkins > Security > Git Host Key Verification Configuration
- For Host Key Verification Strategy, select Manually Provided Keys
- Paste the github.com key into the Approved Host Keys field
- Click Save
Using the Credentials plugin
- Set: [Jenkins Project] > Pipeline > Repositories > Credentials > Add
- View existing: Dashboard > Manage Jenkins > Credentials
- Create new: From Credentials screen > click on appropriate domain (default Global) > Add Credentials
- [image here]
- In the pipeline script, use like:
withCredentials( [usernamePassword( credentialsId: 'test_service_account', usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD') ]) { sh 'echo "Username: $USERNAME"' sh 'echo "Password: $PASSWORD"' } ...
- In code, access them as appropriate to the language:
// Use username and password to connect to the database String username = System.getenv("USERNAME"); String password = System.getenv("PASSWORD"); ...
CycloneDX cdxgen creates SBOMs
- Download cdxgen binary and install
- Basic use:
cdxgen -o sbom.json
- Test:
cdxgen --help
- Many options, shown in help output
- Command places SBOM file in project's root directory
Once SBOM created, CycloneDX also has ability to sign the file:
- Download CycloneDX-CLI and install
- First need to generate signing keypair (only once):
sudo cyclonedx keygen
- Currently only signs XMLs, so convert:
cyclonedx-cli convert --input-file sbom.xml --output-file sbom.json
- Then sign:
cyclonedx sign bom sbom.xml
Generating and validating hashes
- Linux built-in:
shasum
- Use SHA-256:
shasum -a 256 [file]
- Write it to a file:
shasum -a 256 [file] > [hash file]
- Compare a file to its hash:
shasum -c [hash file]
- If the file and its hash match, returns
[file]: OK
- If the file and its hash match, returns
- Compare two hash files:
cmp [hashfile1] [hashfile2]
- If identical, returns nothing
But... shasum
doesn't work on a directory
Options?
- Compute hash on each compiled binary
- Ideally we only compute one hash
- Zip directory, then hash compressed file
tar -zf [archive-name].tar.gz [source-directory]
- where:
-z
uses gzip program for compression-c
create archive (rather than append)-f
archive path and file name
Please see the test project's Jenkinsfile for implementation.