The objective of this article is to share a strategy that has been implemented for a client that asked how we can protect its production branches from having secrets in code.
After few discussions we have highlighted the following requirements:
At this point, you can certainly have serious doubts that a solution can meet all these requirements.
We did actually find one solution that answers all these requirements, the solution is a combination of the following Azure DevOps features.
"Effective September 20, 2023, the secret scanning (CredScan) tool within the Microsoft Security DevOps (MSDO) Extension for Azure DevOps has been deprecated. MSDO secret scanning will be replaced with GitHub Advanced Security for Azure DevOps."
The alternative was to switch with the Gitleaks Azure DevOps extension.
A build validation policy queues a new build when a new PR is created or changes are pushed to an existing PR that targets the branch. The build policy evaluates the build results to determine whether the PR can be completed.
As illustrated in the following diagram our build validation policy will be unique across our repositories and its scan tasks will be located in one yaml file: “secret-scanning.yaml”.
Create a Yaml script file “secret-scanning.yaml” in the git repository “commons” and commit the following code.
This code is the Yaml description of an Azure DevOps pipeline, it is composed of the following actions:
# This is a pipeline that can be used as an Azure DevOps build validation pipeline to prevent secrets from being in the code.
# Reference: https://techcommunity.microsoft.com/t5/azure-developer-community-blog/protect-production-branches-from-having-secrets-through-an-azure/ba-p/3780659?WT.mc_id=DOP-MVP-5003548
# Prerequisite:
# - Disable the option "Protect access to repositories in YAML pipelines" to allow the Azure DevOps Build Service to pull remote repositories. You can find this option by navigating to the project settings page under "Pipeline" > "Settings".
# - Grant version control permissions to the build service, cf https://learn.microsoft.com/en-us/azure/devops/pipelines/scripts/git-commands?view=azure-devops&tabs=yaml&WT.mc_id=DOP-MVP-5003548#grant-version-control-permissions-to-the-build-service
trigger: none
pool:
vmImage: 'ubuntu-latest'
variables:
GIT_USER_EMAIL: "you@example.com"
GIT_USER_NAME: "Your Name"
SOURCE_REPOSITORY_URI: $[variables['System.PullRequest.SourceRepositoryURI']] #Azure DevOps System variable, cf https://learn.microsoft.com/en-us/azure/devops/pipelines/build/variables?view=azure-devops&tabs=yaml&WT.mc_id=DOP-MVP-5003548#system-variables-devops-services
SOURCE_BRANCH: $[variables['System.PullRequest.SourceBranch']] #Azure DevOps System variable
steps:
- checkout: self
clean: true
persistCredentials: true
- script: |
git config --global user.email "$(GIT_USER_EMAIL)"
git config --global user.name "$(GIT_USER_NAME)"
displayName: 'Enable scripts to run Git commands, cf https://learn.microsoft.com/en-us/azure/devops/pipelines/scripts/git-commands?view=azure-devops&tabs=yaml&WT.mc_id=DOP-MVP-5003548#enable-scripts-to-run-git-commands'
name: enableGitCommands
- script: |
#Variable
SOURCE_REPOSITORY_URI=$(SOURCE_REPOSITORY_URI)
REPOSITORY_NAME=$(echo ${SOURCE_REPOSITORY_URI//*\/})
BRANCH_NAME=$(echo ${SOURCE_BRANCH//refs\/heads\/})
SOURCE_REPOSITORY_URI_WITHOUT_USER=$(cut -d @ -f 2 <<< "$SOURCE_REPOSITORY_URI")
SOURCE_REPOSITORY_URI_SUFFIX=$(echo ${SOURCE_REPOSITORY_URI_WITHOUT_USER//https:\/\/})
SOURCE_REPOSITORY_URI="https://$SYSTEM_ACCESSTOKEN@$SOURCE_REPOSITORY_URI_SUFFIX"
#Action
echo "Cleaning the local folder"
ls -lart
rm -rf .git ; rm -rf .gitignore ; rm -rf .dockerignore ; rm -rf ./*
echo "git clone $SOURCE_REPOSITORY_URI ."
git clone $SOURCE_REPOSITORY_URI .
git checkout $BRANCH_NAME
displayName: 'Clone the source repository'
name: gitClone
env:
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
- task: Gitleaks@2
inputs:
scanlocation: '$(Build.SourcesDirectory)'
configtype: 'default'
scanmode: 'nogit'
reportformat: 'sarif'
# Breaking news!"Effective September 20, 2023, the secret scanning (CredScan) tool within the Microsoft Security DevOps (MSDO) Extension for Azure DevOps has been deprecated. MSDO secret scanning will be replaced with GitHub Advanced Security for Azure DevOps."
# - task: MicrosoftSecurityDevOps@1
# displayName: 'Secrets scanning with Microsoft Security DevOps, cf https://learn.microsoft.com/fr-fr/azure/defender-for-cloud/azure-devops-extension?WT.mc_id=DOP-MVP-5003548'
# inputs:
# categories: 'secrets'
# break: true
We need to publish the pipeline in order to use it in our build validation policy.
We will now create a build validation policy to make sure a secret scan is performed whenever a pull request is performed on the production branch “main”.
4. Fill out the “Set build policy” form to use the pipeline we created in the previous step: “Secret scanning with Microsoft Security DevOps” and click on the “Save” icon.
The following screenshot illustrates a pull request that has been blocked by the build validation policy because secrets have been founded in the pull request source repository branch.
The following screenshot illustrates the “Scans” tab of the Azure DevOps pipeline, it prints the secret that have been founded revealing its path and its type, here it is an API Key.
The following screenshot is an Azure DevOps Workbook, it gives a summary of all secrets that have been founded on your organisation. This workbook is available if you go through this setup: “Quickstart: Connect your Azure DevOps repositories to Microsoft Defender for Cloud”.
Azure DevOps scan findings in Defender when the pipeline is located in another repository is currently not supported, a feature request has been done here for information, don’t hesitate to add your vote!
Branch policies help teams protect their important branches of development. Policies enforce your team’s code quality and change management standards. This article was focused on analyzing secrets, but note that the Microsoft Security DevOps extension can be used to perform more general code analysis.
See You in the Cloud
Jamesdld
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.