Every Few months I notice the following Saga repeats. I face a challenge where I need to programmatically manage security aspects of Azure DevOps resources (like Repository, Pipeline, Environment etc.). I do lookup the Azure DevOps REST API documentation, realize that the Permissions & Security API’s are notoriously complicated and inadequately documented. So, I begin with F12 to kick off the Development tools for Browser and intercepting HTTP requests. Trying to guess what’s payloads are exchanged and try to come up with appropriate HTTP requests myself. However strange it might sound, usually this method works for me (actually worked almost all the time). But it’s a painful and time-consuming process. Recently I had to go through this process one more time and I promised to myself that once I am done, I will write a Blog post about it and put the code in a GitHub repository – so next time I will save myself some time & pain. That’s exactly what this post is all about.
Security & Permission REST API
As I have said, the security REST API is complicated and inadequately documented. Typically, each family of resources (work items, Git repositories, etc.) is secured using a different namespace. The first challenge is to find out the namespace IDs.
Then each security namespace contains zero or more access control lists (aka. ACLs). Each access control list contains a token, an inherit flag and a set of zero or more access control entries. Each access control entry contains an identity descriptor, an allowed permissions bitmask, and a denied permissions bitmask.
Tokens are arbitrary strings representing resources in Azure DevOps. Token format differs per resource type; however, hierarchy and separator characters are common between all tokens. Now, where do you find these tokens format? Well, I mostly find them by intercepting the Browser HTTP payloads. To save me from future efforts, I have created a .net Object model around the security namespace IDs, permissions and tokens – so when I consume those libraries, I can ignore these lower-level elements and have a higher order APIs to manage permissions. You can investigate the GitHub repository to learn about it. However, just to make it more fun to use, I have spent a bit time to create a Manifest file (Yes, stolen from Kubernetes world) where I can get my future job done only by writing YAML files – as oppose to .net/C# codes.
Instructions to use
The repository contains two projects (once is a Library – produced a DLL and another is the console executable application) and the console executable is named as
The idea is to create a manifest file (yaml format) and apply the changes via the
> azdoctl apply -f manifest.yaml
You need to create a manifest file to describe your Azure DevOps project and permissions. The format of the manifest file is in yaml (and idea is borrowed from Kubernetes manifest files.)
Here’s the schema of the manifest file:
apiVersion: apps/v1 kind: Project metadata: name: Bi-Team-Project description: Project for BI Engineering team template: name: Agile sourceControlType: Git
Manifest file starts with the team project name and description. Each manifest file can have only one team project definition.
Next, we can define teams for the project with following yaml block:
teams: - name: Bi-Core-Team description: The core team that run BI projects admins: - name: Timothy Green id: 4ae3c851-6ef3-4748-bef9-4f809736d538 - name: Linda id: 9c5918c7-ef03-4059-a49e-aa6e6d761423 membership: groups: - name: 'UX Specialists' id: a2931c86-e975-4220-aa89-dc3f952290f4 users: - name: Timothy Green id: 4ae3c851-6ef3-4748-bef9-4f809736d538 - name: Linda id: 9c5918c7-ef03-4059-a49e-aa6e6d761423
Here we can create teams and assign admins and members to them. All the references (name and ids) must be valid in Azure Active Directory. Ids are Object ID for group or users in Azure Active directory.
Next, we can define the repository – that must be created and assigned permissions to.
repositories: - name: Sample-Git-Repository permissions: - group: 'Data-Scientists' origin: aad allowed: - GenericRead - GenericContribute - CreateBranch - PullRequestContribute - group: 'BI-Scrum-masters' origin: aad allowed: - GenericRead - GenericContribute - CreateBranch - PullRequestContribute - PolicyExempt
Again, you can apply an Azure AD group with very fine-grained permissions to each repository that you want to create.
List of all the allowed permissions:
Administer, GenericRead, GenericContribute, ForcePush, CreateBranch, CreateTag, ManageNote, PolicyExempt, CreateRepository, DeleteRepository, RenameRepository, EditPolicies, RemoveOthersLocks, ManagePermissions, PullRequestContribute, PullRequestBypassPolicy
You can create environments and assign permissions to them with following yaml block.
environments: - name: Development-Environment description: 'Deployment environment for Developers' permissions: - group: 'Bi-Developers' origin: aad roles: - Administrator - name: Production-Environment description: 'Deployment environment for Production' permissions: - group: 'Bi-Developers' origin: aad roles: - User
Build and Release (pipeline) folders
You can also create Folders for build and release pipelines and apply specific permission during bootstrap. That way teams can have fine grained permissions into these folders.
Here’s the snippet for creating build folders.
buildFolders: - path: '/Bi-Application-Builds' permissions: - group: 'Bi-Developers' origin: aad allowed: - ViewBuilds - QueueBuilds - StopBuilds - ViewBuildDefinition - EditBuildDefinition - DeleteBuilds
And, for the release pipelines:
releaseFolders: - path: '/Bi-Application-Relases' permissions: - group: 'Bi-Developers' origin: aad allowed: - ViewReleaseDefinition - EditReleaseDefinition - ViewReleases - CreateReleases - EditReleaseEnvironment - DeleteReleaseEnvironment - ManageDeployments
Once you have the yaml file defined, you can apply it as described above.
That’s it for today. By the way,
The code is provided as-is, with MIT license. You can use it, replicate it, modify it as much as you wish. I would appreciate if you acknowledged the usefulness, but that’s not enforced. You are free to use it anyway you want.
And, that also means, the author is not taking any responsibility to provide any guarantee or such.