Accompanied source code can be found here.
A while ago, I have written an application that could simplify managing Azure DevOps security. The idea was that one could define bunch of YAML file that describes numerous security aspect for an Azure DevOps project (for example, security for teams, build and release folders, repositories etc.) and a pipeline that could sync or apply those security settings to Azure DevOps. Essentially doing GitOps for Azure DevOps and getting a nice readable security documentation as byproduct.
Quite some people have used this, and I was reached out by many to add few more support – specially for Area Paths and iteration paths. This week, I have spent a bit more time – adding these features into the code. Here’s the quick update and instructions how to use it (as of now):
Security as code Samples
Let’s begin seeing some example YAML that the application currently supports:
Project
Here’s the project manifest (YAML) looks like (project.yaml):
apiVersion: apps/v1
kind: Project
metadata:
name: Platform
description: Project for platform team
template:
name: Agile
sourceControlType: Git
The project manifest is required, without it the application will not process any other files.
AAD Groups
The application can support both AAD groups and Azure DevOps groups to be materialized or created respectively. Let’s start with defining an AAD group:
apiVersion: apps/v1
kind: Group
metadata:
name: K8s-Operators
description: An AAD Group that needs to be materialized
properties:
origin: Aad
aadObjectId: eb2a16c0-401a-4fc8-beb4-02fe3e6f25b6
The above manifest will “materialize” the AAD group K8s-Operator
if not already done before, so later we can use this group in other manifests. For AAD group we must set origin: Aad
and provide the Azure AD group object ID as aadObjectId
.
Azure DevOps Groups
Next to AAD group the application supports creating native Azure DevOps groups too:
apiVersion: apps/v1
kind: Group
metadata:
name: SRE-Project-Scoped-Group-001
description: A Group that is project scoped
properties:
origin: Vsts
scope: Project
membership:
groups:
- name: 'IoT-Developers'
origin: Aad
aadObjectId: 00238ebc-66c1-4220-a859-ed0a00243f27
- name: 'K8s-Operators'
origin: Aad
aadObjectId: eb2a16c0-401a-4fc8-beb4-02fe3e6f25b6
users:
- name: Timothy Green
principal: timothy@cloudoven.net
- name: Linda
principal: Linda@cloudoven.net
In order to create Azure DevOps native groups, we must provide origin: Vsts
and an appropriate value for scope
. Scope can be Project
scoped or Organization
scoped. A native Azure DevOps group can have members that are AAD group or another AzDO native group, and of course direct members that are described by their principals
.
Area Paths
We can define Area Paths and their permissions using an Area Path manifest like below:
apiVersion: apps/v1
kind: AreaPathSecurity
metadata:
name: AreaPathSecurity
description: Sample that applies permissions across multiple area paths
permissions:
- paths:
- Platform/Marketing/Frontdesk
- Platform/Finance
- Platform/Finance/LoanSector
allowed:
- GENERIC_READ
- GENERIC_WRITE
- CREATE_CHILDREN
- DELETE
- WORK_ITEM_READ
- WORK_ITEM_WRITE
- MANAGE_TEST_PLANS
- MANAGE_TEST_SUITES
groups:
- group: 'K8s-Operators'
origin: Aad
aadObjectId: eb2a16c0-401a-4fc8-beb4-02fe3e6f25b6
users:
- name: Timothy
principal: timothy@cloudoven.net
You can allow permissions for a certain number of groups (can be both AAD groups or Azure DevOps groups) or users.
Iteration Path
Like Area Path we can also define Iteration Paths and their permissions:
apiVersion: apps/v1
kind: IterationPathSecurity
metadata:
name: IterationPathSecurity
description: Sample that applies permissions across multiple Iteration paths
permissions:
- paths:
- Platform/GA
- Platform/GA/CommunityRelease
- Platform/GA/CTP1
allowed:
- GENERIC_READ
- GENERIC_WRITE
- CREATE_CHILDREN
- DELETE
groups:
- group: 'K8s-Operators'
origin: Aad
aadObjectId: eb2a16c0-401a-4fc8-beb4-02fe3e6f25b6
users:
- name: Timothy
principal: timothy@cloudoven.net
Teams
We can define Teams, along with the administrators of the team, members and map them to a certain Area path.
apiVersion: apps/v1
kind: Team
metadata:
name: PO-TEAM
description: A team for Product owners
admins:
- name: Timothy Green
principal: timothy@cloudoven.net
- name: Moim
principal: moim@cloudoven.net
membership:
groups:
- name: 'K8s-Operators'
origin: Aad
aadObjectId: eb2a16c0-401a-4fc8-beb4-02fe3e6f25b6
users:
- name: Timothy Green
principal: timothy@cloudoven.net
- name: Linda
principal: Linda@cloudoven.net
- name: Scrum
principal: Scrum@cloudoven.net
config:
defaultPath: Platform/Marketing/Frontdesk
areaPaths:
- path: 'Platform/Finance/South Americas'
includeSubAreas: true
- path: 'Platform/Marketing/Frontdesk'
includeSubAreas: true
- path: 'Platform/HR/Internal'
includeSubAreas: true
As we can see the team manifest is quite richer than earlier version. It now allows you to define admins, members but also allows mapping multiple area paths (including their sub areas).
Repository
We can define permissions for repositories (one or more repositories in a single manifest file):
apiVersion: apps/v1
kind: RepositorySecurity
metadata:
name: RepositorySecurity
description: Sample that applies permissions across multiple repositories.
permissions:
- names:
- React-JS
- Mobile-App
allowed:
- GenericRead
- GenericContribute
- CreateBranch
- PullRequestContribute
groups:
- group: 'K8s-Operators'
origin: Aad
aadObjectId: eb2a16c0-401a-4fc8-beb4-02fe3e6f25b6
users:
- name: Timothy
principal: timothy@cloudoven.net
One thing to note, if the repository doesn’t exist the application will NOT create one.
Build Folders
YAML pipeline folders or classic build folders can be managed with following example manifest.
apiVersion: apps/v1
kind: PipelineFolderSecurity
metadata:
name: PipelineFolderSecurity
description: Sample that applies permissions across multiple pipeline folders
permissions:
- paths:
- \Demo-Folder\Child-Folder\X86
- \Demo-Folder\Child-Folder\X64
allowed:
- ViewBuilds
- QueueBuilds
- StopBuilds
- ViewBuildDefinition
- EditBuildDefinition
groups:
- group: 'K8s-Operators'
origin: Aad
aadObjectId: eb2a16c0-401a-4fc8-beb4-02fe3e6f25b6
users:
- name: Timothy
principal: cloudoven.net
Release folders
Classic release folders can be managed as below:
apiVersion: apps/v1
kind: ReleaseFolderSecurity
metadata:
name: ReleaseFolderSecurity
description: Sample that applies permissions across multiple release folders
permissions:
- paths:
- \Demo-Folder\Child-Folder\X86
- \Demo-Folder\Child-Folder\X64
allowed:
- ViewReleaseDefinition
- EditReleaseDefinition
- ViewReleases
- CreateReleases
- EditReleaseEnvironment
- DeleteReleaseEnvironment
- ManageDeployments
groups:
- group: 'K8s-Operators'
origin: Aad
aadObjectId: eb2a16c0-401a-4fc8-beb4-02fe3e6f25b6
users:
- name: Timothy
principal: timothy@cloudoven.net
Run it!
Let’s say we have bunch of these manifest files into a directory, then we can lunch the application to process all of these one after another.
docker run --rm \
-v "/mnt/c/Git/Manifests:/home/payload" \
moimhossain/azdoctl:gama apply -d "/home/payload" \
-u "https://dev.azure.com/<ORG NAME>" \
-p "<YOUR PAT>" \
-k "APP INSIGHT CONNECTION STRING"
Alternatively, you can run a single manifest file – specifically:
docker run --rm \
-v "/mnt/c/Git/Manifests:/home/payload"
moimhossain/azdoctl:gama apply \
-f "/home/payload/Project.yml" \
-u "https://dev.azure.com/<ORG NAME>" \
-p "<YOUR PAT>" \
-k "APP INSIGHT CONNECTION STRING"
This produces the logs into the console as it processes the manifests:

Conclusion
Azure DevOps security is crucial for businesses that want to stay ahead of the game in terms of security standards. In recent years, the importance of security in the DevOps process has skyrocketed, and there is no doubt that security has become essential for businesses of all sizes. However, most businesses still view security as a separate task and often fail to integrate it into their development process. That’s where Azure DevOps security as Code comes to the rescue.
Azure DevOps security as Code allows businesses to incorporate security into their development process by automating security testing and ensuring that the security aspect of their code is in line with their requirements. With Azure DevOps security, businesses can create automated security testing pipelines that can help detect and prevent any security issues before they become an issue in production.
By adopting Infrastructure As Code (IAC) and Docker-based operations, businesses can quickly deploy infrastructure and applications with Azure DevOps, reducing errors in manual processes and increasing agility. Furthermore, with the Azure DevOps security features, businesses can take control of security with command-line management, enhancing interactions between teams, enabling better testing and deployment practices, and helping adopt and optimize continuous integration and delivery (CI/CD) pipelines.
In conclusion, Azure DevOps security as Code is an essential tool that can help businesses secure their code, ensure that their development process is in line with their security requirements, and mitigate any security threats in a fast and convenient manner. With technology trends evolving and security threats becoming more significant, businesses must be proactive in their approach to security, and Azure DevOps security as Code is the way to go.
Hope you find this useful. Thanks for reading.