Insights

Secure Azure DevOps Practices for Enhanced Compliance and Efficiency

Written by Mark Panthofer | 8/28/24 5:57 PM

Ensuring the security and compliance of your DevOps practices is crucial. Azure DevOps offers many great ways to manage your development lifecycle, but without proper configuration, you can still expose your organization to significant risks.

At nvisia, we have developed a set of seven baseline security practices to help you deploy a secure and compliant Azure DevOps organization. Here's an overview of those practices.

Baseline Security Practices for Azure DevOps

Practice 1: Never, ever assign any member of the project team to the Project Admin group! ...but also, do not hinder the team's velocity.

Allowing a project team member to be part of the Project Admin permission group is akin to handing over the keys to the kingdom.

By granting such extensive privileges, you essentially relinquish the standard controls and safeguards provided by Azure DevOps, leaving your organization vulnerable to potential risks and security breaches. To maintain a robust security posture and adhere to best practices, it is imperative to assign Project Admin permissions to individuals outside of the project team, mirroring the segregation of duties principle commonly observed in IT environments.

This fundamental principle of segregating duties is not just a recommended practice but a cornerstone of any reputable security and compliance framework. In the realm of cybersecurity, the NIST Cybersecurity Framework emphasizes the importance of Protective Technology (PR.PT), highlighting the necessity of distributing critical system functions among different roles to mitigate the risk of unauthorized changes.

By adopting a structured approach to access control and permissions management, organizations can fortify their defenses and minimize the likelihood of security incidents.

While it is crucial, many agile developers may argue that they cannot function effectively without the Project Admin privileges or a team member with such authority. This is a valid concern, especially considering that the default Contributor group permissions may be overly restrictive for teams focused on cloud-native development.

The key lies in finding a harmonious balance between compliance and developer productivity. To achieve this, creating a bespoke permission group modeled after the Azure DevOps Contributor group is essential. This new group, known as the Contributor-Plus, grants specific powers necessary for software development without the need for excessive service requests. Typically, members of this group are equipped to create pipelines, repositories, and iterations, striking a balance between security and operational efficiency.

Practice 2: Choose to leverage the Azure API and Infrastructure as Code (IaC) instead of relying on the Azure DevOps UI.

To facilitate the first practice (above), it's essential to devise a method for managing permissions across your organization's projects.

It's important to note that manually adding permissions to groups via the Azure DevOps UI can be cumbersome and limited. Moreover, this approach often results in a lack of consistency among project teams, which can lead to a nightmare during attestation.

Therefore, the most effective method for managing customer permissions is to utilize the Azure API, or even better, employ Terraform/OpenTofu providers to encapsulate the API within declarative configuration code. Our approach involves controlling these permissions and monitoring for any deviations using Terraform/OpenTofu, which is automated within a platform engineering project repository and pipeline.

Once the Contributor-Plus group and any other necessary custom groups are established, ensure that users can only be added to these groups through an IAM process, typically involving Azure Entra ID security group assignments.

Practice 3: Embrace Entra ID integration for enhanced segregation of duties and targeted permissions.

Bid farewell to manual user additions and sporadic assignments within your Azure DevOps permission groups!

Exclusively allocate members through Azure Entra ID groups to bolster the security of your Azure DevOps environment. Streamline the process by seamlessly mapping security groups to Azure DevOps (AzDO) permission groups with precise role granularity, all managed through Entra ID for a centralized access control solution.

Leverage the power of the Azure API or opt for the more advanced Terraform/OpenTofu IaC methods to seamlessly establish the link between Entra ID and Azure DevOps Project Permission groups. With this automated approach, only the designated agent, secured running the permission update pipeline will possess Project Admin rights, safeguarding against unauthorized user additions and ensuring a consistent, secure, and streamlined access management strategy.

As a bonus with Entra ID integration, your security posture will improve with features including mandatory multifactor authentication and conditional access policies. 

Practice 4: Enable Azure DevOps security event auditing

Implement a robust logging mechanism to track user actions effectively.

Azure DevOps empowers organization Owners and Project Collection Administrators to activate "Auditing" features, capturing detailed activity logs within your Azure DevOps setup. Enhance this by seamlessly channeling audit events to a Splunk-compatible destination. This allows your security and compliance teams to actively monitor the log stream and trigger alerts aligned with your organization's compliance protocols.

Practice 5: Define and enforce secure repository policies to manage access and maintain code integrity. 

To begin, ensure that you exclude development team members from the Project Admin permission group to prevent any unauthorized modifications or overrides by the team. Instead, utilize the Contributor-Plus role for technical leaders who require additional permissions beyond the standard Contributor group.

Next, align your development workflows with trunk-based development principles and safeguard the main (trunk) branch.

When setting policies for reviewing code merges into the main branch in Azure DevOps, it's important to enforce practices that ensure code quality, security, and maintainability. Here are the recommended approaches:

Branch protection guidelines
      1. Require pull request (PR) reviews: Configure the main branch to require at least one or more PR reviews before any new or changed code can be merged. This ensures that all changes are reviewed by other team members, which helps maintain code quality and catch potential issues early.
      2. Enforce code owner approvals: If your repository uses code owners (aka, lead developers or complex subsystem owners), make it mandatory that the code owner(s) approve changes before they can be merged into the main branch. This ensures that the most knowledgeable team members review critical areas of the codebase. This also services a great training and mentoring exercise.
Continuous integration (CI) policies
      1. Build validation: Set up a policy that requires the code to successfully pass a build process before it can be merged into the main branch. This helps catch build-breaking changes before they are introduced to the main branch.
      2. Automated testing: Integrate automated tests into the CI pipeline and require that all tests pass before the merge is allowed. This ensures that new changes do not introduce regressions or break existing functionality. Start with automated unit tests, then move to integration and smoke test as part of PR pre-merge pipeline. 
Compliance and security checks
      1. Static code analysis: Implement static code analysis as part of the PR process. Ensure that the code meets security and style guidelines before it is merged. Tools like SonarQube or Checkmarx static analysis tools can be integrated into the pipeline.
      2. Dependency scanning: Include dependency scanning tools like JFrog XRay to check for known vulnerabilities in third-party libraries or components. Additionally, licenses for open-source components and libraries should be scanned for violations. Any issues identified should be resolved before the merge is allowed.
Enforce policies via branch settings
      1. Prevent direct commits to main branch: Disable direct commits to the main branch to ensure that all changes go through the PR process. This reduces the risk of unreviewed code being introduced into the production codebase.
      2. Require linked work items: Enforce a policy that requires each PR to be linked to a work item (e.g., a user story or bug). This helps track changes and ensures that all code changes are associated with a documented task or issue.  
By implementing these policies, organizations can maintain a high level of code quality, ensure security, and keep their main branch stable and production-ready.
Practice 6: Secure pipelines and service connections

Setting up your pipelines and service connections in Azure DevOps is a crucial step that is frequently underestimated, leading to missed opportunities in enhancing security and compliance measures. Here are some essential practices for doing this the right way:

    1. Use appropriate role based access control to manage pipelines, build agents, and service connections: Again, these and any sort of permission controls only work if you tightly manage the Project Admin role. Be especially sure to lock down Service Connections to upper-level environments.
    2. Use private build agents: Use private build agents deployed in isolated subnets for each environment or landing zone. This limits the blast radius of any potential security incidents and ensures that build agents are only interacting with resources within their assigned environment​​.
    3. Use approval tasks in pipelines: Enforce the use of approval tasks within the pipelines to maintain control over deployments. This ensures that critical deployments require manual review and approval before proceeding​. In Azure DevOps you can add approval steps to required pipeline templates. 
    4. Use Azure DevOps service connections: Use least privilege permissioned service connections to operate on resources such as Kubernetes clusters during a code deployment. Many teams still use cluster admin credentials for deployments, leaving the keys to the castle under the doormat. Therefore, each service connection should be granted only the permissions necessary for its specific task in a specific landing zone and/or environment. Especially with AWS resource connections, avoid using build agents with universal identities that can assume any role, just by know the name of the role​​.
    5. Use Service Connection Checks: Implement checks to ensure that releases are from the main branch. This enforces that all changes, including application and infrastructure have passed a peer-reviewed process, maintaining segregation of duties​. Properly managing pipeline service connections is crucial for compliance. Create read-only service connections for plan and dry runs, and enforce service connection checks and approvals.
Practice 6: Move toward a Zero Trust Architecture

Make sure that Azure DevOps access is restricted to corporate private networks and secure your network using TLS 1.3. Additionally, make sure to access your cloud resources through controlled Azure DevOps Service Connections and the pipelines run on private agents, deployed to a private network segment.

In a hub and spoke architecture, this means the build agent can only route traffic within the target spoke, limiting the network blast area. Additionally, the Service Connection's identity must have RBAC access to the resource once the target private network. 

Practice 7: Secrets management

To further enhance security and control over sensitive information, it is crucial to implement a robust strategy for managing secrets in your Azure DevOps environment. By utilizing tools like Azure Key Vault, you can ensure that confidential data is securely stored and accessed only by authorized users.

Consider deploying Remote Key Vaults on a private network, within a specific target spoke, to provide an additional layer of isolation and control over your Azure DevOps central secret variables. This setup enhances the security of your secrets and minimizes the risk of unauthorized access.

In Azure Pipelines, leverage secure tasks to access your Key Vault, such as the AzureKeyVault@1 task, which requires an Azure Service Connection. This connection, typically an Azure Service Principle with RBAC access to the target Azure Key Vault resource, acts as a secure gateway for retrieving sensitive information from the Key Vault.

To ensure the utmost security, it is imperative to properly secure the service connection with access controls and checks. By following these best practices for secrets management, you can fortify the protection of your confidential data and maintain a high level of security within your Azure DevOps environment.

Conclusion

By following these practices, you can significantly enhance the security and compliance of your Azure DevOps environment. At nvisia, we are committed to helping you achieve a secure and efficient DevOps workflow. Contact us to learn more about our Digital Foundations service and how we can assist you in your cloud-native journey.