Skip to content

2024/04

Repository Strategy: Fork vs Branch

In this post, I will explain the different ways to contribute to a Git repository: Fork vs Branch.

Fork

A fork is a copy of a repository that you can make changes to without affecting the original repository. When you fork a repository, you create a new repository in your GitHub account that is a copy of the original repository.

The benefits of forking a repository include:

  • Isolation: You can work on your changes without affecting the original repository.
  • Collaboration: You can make changes to the forked repository and submit a pull request to the original repository to merge your changes.
  • Ownership: You have full control over the forked repository and can manage it as you see fit.

The challenges of forking a repository include:

  • Synchronization: Keeping the forked repository up to date with the original repository can be challenging.
  • Conflicts: Multiple contributors working on the same codebase can lead to conflicts and merge issues.
  • Visibility: Changes made to the forked repository are not visible in the original repository until they are merged.

Branch

A branch is a parallel version of a repository that allows you to work on changes without affecting the main codebase. When you create a branch, you can make changes to the code and submit a pull request to merge the changes back into the main branch.

The benefits of using branches include:

  • Flexibility: You can work on different features or bug fixes in separate branches without affecting each other.
  • Collaboration: You can work with other developers on the same codebase by creating branches and submitting pull requests.
  • Visibility: Changes made in branches are visible to other developers, making it easier to review and merge changes.

The challenges of using branches include:

  • Conflicts: Multiple developers working on the same branch can lead to conflicts and merge issues.
  • Complexity: Managing multiple branches can be challenging, especially in large projects.
  • Versioning: Branches are versioned separately, making it harder to track changes across the project.

Fork vs Branch

The decision to fork or branch a repository depends on the project's requirements and the collaboration model.

  • Fork: Use a fork when you want to work on changes independently of the original repository or when you want to contribute to a project that you do not have write access to.

  • Branch: Use a branch when you want to work on changes that will be merged back into the main codebase or when you want to collaborate with other developers on the same codebase.

For my IaC project with Terraform, I will use branches to work on different features and bug fixes and submit pull requests to merge the changes back into the main branch. This approach will allow me to collaborate with other developers and keep the codebase clean and organized.

Repository Strategy: Monorepo vs Multi-repo

In this post, I will explain the repository strategy that I will use for my Infrastructure as Code (IaC) project with Terraform.

Monorepo

A monorepo is a single repository that contains all the code for a project.

The benefits of using a monorepo include:

  • Simplicity: All the code is in one place, making it easier to manage and maintain.
  • Consistency: Developers can easily see all the code related to a project and ensure that it follows the same standards and conventions.
  • Reusability: Code can be shared across different parts of the project, reducing duplication and improving consistency.
  • Versioning: All the code is versioned together, making it easier to track changes and roll back if necessary.

The challenges of using a monorepo include:

  • Complexity: A monorepo can become large and complex, making it harder to navigate and understand.
  • Build times: Building and testing a monorepo can take longer than building and testing smaller repositories.
  • Conflicts: Multiple developers working on the same codebase can lead to conflicts and merge issues.

Multi-repo

A multi-repo is a set of separate repositories that contain the code for different parts of a project.

The benefits of using a multi-repo include:

  • Isolation: Each repository is independent, making it easier to manage and maintain.
  • Flexibility: Developers can work on different parts of the project without affecting each other.
  • Scalability: As the project grows, new repositories can be added to manage the code more effectively.

The challenges of using a multi-repo include:

  • Complexity: Managing multiple repositories can be more challenging than managing a single repository.
  • Consistency: Ensuring that all the repositories follow the same standards and conventions can be difficult.
  • Versioning: Each repository is versioned separately, making it harder to track changes across the project.

Conclusion

For my IaC project with Terraform, I will use a monorepo approach to manage all the Terraform modules and configurations for my project.

Terraform: Configuration Language

After deciding to use Terraform for my Infrastructure as Code (IaC) project, Terraform configuration language must be understanded to define the desired state of my infrastructure.

Info

I will update this post with more information about Terraform configuration language in the future.

Terraform uses a declarative configuration language to define the desired state of your infrastructure. This configuration language is designed to be human-readable and easy to understand, making it accessible to both developers and operations teams.

Declarative vs. Imperative

Terraform's configuration language is declarative, meaning that you define the desired state of your infrastructure without specifying the exact steps needed to achieve that state. This is in contrast to imperative languages, where you specify the exact sequence of steps needed to achieve a desired outcome.

For example, in an imperative language, you might write a script that creates a virtual machine by executing a series of commands to provision the necessary resources. In a declarative language like Terraform, you would simply define the desired state of the virtual machine (e.g., its size, image, and network configuration) and let Terraform figure out the steps needed to achieve that state.

Configuration Blocks

Terraform uses configuration blocks to define different aspects of your infrastructure. Each block has a specific purpose and contains configuration settings that define how that aspect of your infrastructure should be provisioned.

For example, you might use a provider block to define the cloud provider you want to use, a resource block to define a specific resource (e.g., a virtual machine or storage account), or a variable block to define input variables that can be passed to your configuration.

provider "azurerm" {
  features {}
}

resource "azurerm_resource_group" "example" {
  name     = "example-resources"
  location = "East US"
}

variable "location" {
  type    = string
  default = "East US"
}

Variables

Terraform allows you to define variables that can be used to parameterize your configuration. Variables can be used to pass values into your configuration, making it easier to reuse and customize your infrastructure definitions.

variable "location" {
  type    = string
  default = "East US"
}

resource "azurerm_resource_group" "example" {
  name     = "example-resources"
  location = var.location
}

locals

Terraform allows you to define local values that can be used within your configuration. Locals are similar to variables but are only available within the current module or configuration block.

variable "location" {
  type    = string
  default = "East US"
}

locals {
  resource_group_name = "example-resources"
}

resource "azurerm_resource_group" "example" {
  name     = local.resource_group_name
  location = var.location
}

Data Sources

Terraform allows you to define data sources that can be used to query external resources and retrieve information that can be used in your configuration. Data sources are read-only and can be used to fetch information about existing resources, such as virtual networks, storage accounts, or database instances.

data "azurerm_resource_group" "example" {
  name = "example-resources"
}

resource "azurerm_virtual_network" "example" {
  name                = "example-network"
  location            = data.azurerm_resource_group.example.location
  resource_group_name = data.azurerm_resource_group.example.name
}

Functions

try

The try function allows you to provide a default value in case an expression returns an error. This can be useful when working with optional values that may or may not be present.

variable "optional_value" {
  type    = string
  default = null
}

locals {
  value = try(var.optional_value, "default_value")
}

Debugging Terraform

You can use the TF_LOG environment variable to enable debug logging in Terraform. This can be useful when troubleshooting issues with your infrastructure or understanding how Terraform is executing your configuration.

export TF_LOG=DEBUG
terraform plan

TOu can use the following decreasing verbosity levels log: TRACE, DEBUG, INFO, WARN or ERROR

To persist logged output logs in a file:

export TF_LOG_PATH="terraform.log"

To separare logs for Terraform and provider, you can use the following environment variables TF_LOG_CORE and TF_LOG_PROVIDER respectively. For example, to enable debug logging for both Terraform and the Azure provider, you can use the following environment variables:

export TF_LOG_CORE=DEBUG
export TF_LOG_PATH="terraform.log"

or

export TF_LOG_PROVIDER=DEBUG
export TF_LOG_PATH="provider.log"

To disable debug logging, you can unset the TF_LOG environment variable:

unset TF_LOG

References

Terraform: Set your local environment developer

I wil use Ubuntu in WSL v2 as my local environment for my IaC project with Terraform. I will install the following tools:

  • vscode
  • Trunk
  • tenv
  • az cli

az cli

I will use the Azure CLI to interact with Azure resources from the command line. I will install the Azure CLI using the following commands:

curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash

vscode

I will use Visual Studio Code as my code editor for my IaC project with Terraform. I will install the following extensions:

  • Terraform
  • Azure Terraform
  • Azure Account
  • Trunk

tenv

tenv is a tool that allows you to manage multiple Terraform environments with ease. It provides a simple way to switch between different environments, such as development, staging, and production, by managing environment variables and state files for each environment.

Installation

You can install tenv using go get:

LATEST_VERSION=$(curl --silent https://api.github.com/repos/tofuutils/tenv/releases/latest | jq -r .tag_name)
curl -O -L "https://github.com/tofuutils/tenv/releases/latest/download/tenv_${LATEST_VERSION}_amd64.deb"
sudo dpkg -i "tenv_${LATEST_VERSION}_amd64.deb"

Usage

To create a new environment, you can use the tenv create command:

# to install the latest version of Terraform
tenv tf install 

References

Starting my IaC project with terraform

This is not my first IaC project but I want to share with you some key considerations that I have in mind to start a personal IaC project with Terraform based on post What you need to think about when starting an IaC project ?

1. Define Your Goals

These are my goals:

  • Automate the provisioning of infrastructure
  • Improve consistency and repeatability
  • Reduce manual effort
  • Enable faster deployments

2. Select the Right Tools

For my project I will use Terraform because I am familiar with it and I like its declarative configuration language.

3. Design Your Infrastructure

In my project, I will use a modular design that separates my infrastructure into different modules, such as networking, compute, and storage. This will allow me to reuse code across different projects and make my infrastructure more maintainable.

4. Version Control Your Code

I will use Git for version control and follow best practices for version control, such as using descriptive commit messages and branching strategies.

5. Automate Testing

Like appear in Implement compliance testing with Terraform and Azure, I'd like to implement:

  • Compliance testing
  • End-to-end testing
  • Integration testing

6. Implement Continuous Integration/Continuous Deployment (CI/CD)

I set up my CI/CD pipelines with Github Actions.

7. Monitor and Maintain Your Infrastructure

I will use Azure Monitor to monitor my infrastructure and set up alerts to notify me of any issues. I will also regularly review and update my infrastructure code to ensure that it remains up to date and secure.

Of course I don't have all the answers yet, but I will keep you updated on my progress and share my learnings along the way. Stay tuned for more updates on my IaC project with Terraform!

What you need to think about when starting an IaC project ?

Infrastructure as Code (IaC) is a key practice in modern software development that allows you to manage your infrastructure in a declarative manner. With IaC, you can define your infrastructure using code, which can be version-controlled, tested, and deployed automatically. This approach brings several benefits, such as increased consistency, repeatability, and scalability.

When starting an IaC project, there are several key considerations you need to keep in mind to ensure its success. In this article, we will discuss some of the key things you should think about when embarking on an IaC project.

1. Define Your Goals

Before you start writing any code, it's essential to define your goals for the IaC project. What are you trying to achieve with IaC? Are you looking to automate the provisioning of infrastructure, improve consistency, or increase scalability? By clearly defining your goals, you can ensure that your IaC project is aligned with your organization's objectives.

Some examples:

  • Automate the provisioning of infrastructure
  • Improve consistency and repeatability
  • Increase scalability and reduce manual effort
  • Enhance security and compliance
  • Enable faster development and deployment cycles

2. Select the Right Tools

Choosing the right tools is crucial for the success of your IaC project. There are several IaC tools available, such as Terraform, Ansible, and AWS CloudFormation, each with its strengths and weaknesses. Consider factors such as ease of use, scalability, and integration with your existing tools when selecting an IaC tool.

Some examples:

  • Terraform: A popular IaC tool that allows you to define your infrastructure using a declarative configuration language.
  • Ansible: A configuration management tool that can also be used for IaC.
  • AWS CloudFormation: A service provided by AWS that allows you to define your infrastructure using JSON or YAML templates.
  • Azure Resource Manager (ARM) templates: A service provided by Azure that allows you to define your infrastructure using JSON templates.
  • Bicep: A domain-specific language for defining Azure resources that compiles to ARM templates.
  • Pulumi: A tool that allows you to define your infrastructure using familiar programming languages such as Python, JavaScript, and Go.
  • Chef: A configuration management tool that can also be used for IaC.

3. Design Your Infrastructure

When designing your infrastructure, think about how you want to structure your code. Consider using modular designs that allow you to reuse code across different projects. Define your infrastructure in a way that is easy to understand and maintain, and follow best practices for code organization.

4. Version Control Your Code

Version control is a fundamental practice in software development, and it is equally important for IaC projects. By using version control systems such as Git, you can track changes to your infrastructure code, collaborate with team members, and roll back changes if needed. Make sure to follow best practices for version control, such as using descriptive commit messages and branching strategies.

Some examples:

  • Use Git for version control
  • Use branching strategies like Microsoft Flow or GitHub Flow to manage your codebase
  • Use pull requests for code reviews
  • Automate your CI/CD pipelines to run tests and deploy changes
  • Use tags to mark releases or milestones

5. Automate Testing

Testing is an essential part of any software development project, and IaC is no exception. Automating your tests can help you catch errors early in the development process and ensure that your infrastructure code is working as expected. Consider using tools such as Terraform's built-in testing framework or third-party testing tools to automate your tests.

Some examples:

  • Use Terraform's built-in testing framework to write unit tests for your infrastructure code
  • Use tools like Terratest or Kitchen-Terraform to write integration tests for your infrastructure code
  • Use static code analysis tools to check for common errors and best practices in your infrastructure code, like Terraform's terraform validate command, or tools like tfsec or checkov.
  • Use linting tools to enforce coding standards and style guidelines in your infrastructure code, like Terraform's terraform fmt command, or tools like tflint or checkov.
  • Use security scanning tools to identify potential security vulnerabilities in your infrastructure code.

6. Implement Continuous Integration/Continuous Deployment (CI/CD)

CI/CD pipelines are a key component of modern software development practices, and they are equally important for IaC projects. By implementing CI/CD pipelines, you can automate the testing, building, and deployment of your infrastructure code, reducing the risk of errors and speeding up the development process. Consider using tools such as Github or Azure DevOps to set up your CI/CD pipelines.

Use tools like Terraform Cloud, Azure DevOps, or Github Actions to automate your CI/CD pipelines.

7. Monitor and Maintain Your Infrastructure

Once your IaC project is up and running, it's essential to monitor and maintain your infrastructure. Implement monitoring solutions that allow you to track the health and performance of your infrastructure, and set up alerts to notify you of any issues. Regularly review and update your infrastructure code to ensure that it remains up-to-date and secure.

By keeping these key considerations in mind when starting an IaC project, you can set yourself up for success and ensure that your infrastructure is managed efficiently and effectively. IaC is a powerful practice that can help you automate and scale your infrastructure, and by following best practices, you can maximize the benefits of this approach.

How to create a Management Group diagram with draw.io

I nedd to create a diagram of the Management Groups in Azure, and I remembered a project that did something similar but with PowerShell: https://github.com/PowerShellToday/new-mgmgroupdiagram.

Export your Management Group structure from Azure Portal or ask for it

If you can access the Azure Portal, you can export the Management Group structure to a CSV file. To do this, follow these steps:

  1. Go to the Azure portal.
  2. Navigate to Management groups.
  3. Click on Export.
  4. Save the CSV file to your local machine.

If you don't have access to the Azure Portal, you can ask your Azure administrator to export the Management Group structure for you.

The file has the following columns:

  • id: The unique identifier of the Management Group or subscription.
  • displayName: The name of the Management Group or subscription.
  • itemType: The type of the item (Management Group or subscription).
  • path: The path to the management or subscription group, its parent.
  • accessLevel: Your access level.
  • childSubscriptionCount: The number of child subscriptions at this level.
  • totalSubscriptionCount: The total number of subscriptions.

Create a CSV to be imported into draw.io

  1. Import the CSV file to excel, rename the sheet to "Export_Portal"
  2. Create a second sheet with the following columns:
    • id: reference to the id in the first sheet
    • displayName: reference to the displayName in the first sheet
    • itemType: reference to the itemType in the first sheet
    • ParentId: Use the following formula to get the parent of the current item:
      =IF(ISERROR(FIND(","; Export_Portal!D2)); Export_Portal!D2; TRIM(RIGHT(SUBSTITUTE(Export_Portal!D2; ","; REPT(" "; LEN(Export_Portal!D2))); LEN(Export_Portal!D2))))
      
  3. Export the second sheet to a CSV file.

Import the CSV file into draw.io

  1. Go to draw.io and create a new diagram.
  2. Click on Arrange > Insert > Advanced > CSV.
  3. Insert the header for the columns: id, displayName, itemType, Parent:

        #label: %displayName%
        #stylename: itemType
        #styles: {"Management Group": "label;image=img/lib/azure2/general/Management_Groups.svg;whiteSpace=wrap;html=1;rounded=1; fillColor=%fill%;strokeColor=#6c8ebf;fillColor=#dae8fc;points=[[0.5,0,0,0,0],[0.5,1,0,0,0]];",\
        #"Subscription": "label;image=img/lib/azure2/general/Subscriptions.svg;whiteSpace=wrap;html=1;rounded=1; fillColor=%fill%;strokeColor=#d6b656;fillColor=#fff2cc;points=[[0.5,0,0,0,0],[0.5,1,0,0,0]];imageWidth=26;"}
        #
        #
        #namespace: csvimport-
        #
        #connect: {"from": "ParentId", "to": "displayName", "invert": true, "style": "curved=1;endArrow=blockThin;endFill=1;fontSize=11;edgeStyle=orthogonalEdgeStyle;"}
        #
        ## Node width and height, and padding for autosize
        #width: auto
        #height: auto
        #padding: -12
        #
        ## ignore: id,image,fill,stroke,refs,manager
        #
        ## Column to be renamed to link attribute (used as link).
        ## link: url
        #
        ## Spacing between nodes, heirarchical levels and parallel connections.
        #nodespacing: 40
        #levelspacing: 100
        #edgespacing: 40
        #
        ## layout: auto
        #layout: verticaltree
        #
        ## ---- CSV below this line. First line are column names. ----
    
    4. Paste the content of the CSV file and click on Import.

You should see a diagram with the Management Groups and Subscriptions.

For example:

This is the common structure for the Management Groups in the Enterprise Scale Landing Zone, now Accelerator Landing Zone:

    graph TD
        A[Root Management Group] --> B[Intermediary-Management-Group]
        B --> C[Decommissioned]
        B --> D[Landing Zones]
        B --> E[Platform]
        B --> F[Sandboxes]
        D --> G[Corp]
        D --> H[Online]
        E --> I[Connectivity]
        E --> J[Identity]
        E --> K[Management]        

And this is the CSV file to import into draw.io:

#label: %displayName%
#stylename: itemType
#styles: {"Management Group": "label;image=img/lib/azure2/general/Management_Groups.svg;whiteSpace=wrap;html=1;rounded=1; fillColor=%fill%;strokeColor=#6c8ebf;fillColor=#dae8fc;points=[[0.5,0,0,0,0],[0.5,1,0,0,0]];",\
#"Subscription": "label;image=img/lib/azure2/general/Subscriptions.svg;whiteSpace=wrap;html=1;rounded=1; fillColor=%fill%;strokeColor=#d6b656;fillColor=#fff2cc;points=[[0.5,0,0,0,0],[0.5,1,0,0,0]];imageWidth=26;"}
#
#
#namespace: csvimport-
#
#connect: {"from": "ParentId", "to": "displayName", "invert": true, "style": "curved=1;endArrow=blockThin;endFill=1;fontSize=11;edgeStyle=orthogonalEdgeStyle;"}
#
## Node width and height, and padding for autosize
#width: auto
#height: auto
#padding: -12
#
## ignore: id,image,fill,stroke,refs,manager
#
## Column to be renamed to link attribute (used as link).
## link: url
#
## Spacing between nodes, heirarchical levels and parallel connections.
#nodespacing: 40
#levelspacing: 100
#edgespacing: 40
#
## layout: auto
#layout: verticaltree
#
## ---- CSV below this line. First line are column names. ----
id,displayName,itemType,ParentId
1,Tenant Root Group,Management Group,
2,Intermediary Management Group,Management Group,Tenant Root Group
3,Decommissioned,Management Group,Intermediary Management Group
4,Landing Zones,Management Group,Intermediary Management Group
5,Platform,Management Group,Intermediary Management Group
6,Sandboxes,Management Group,Landing Zones
7,Corp,Management Group,Landing Zones
8,Online,Management Group,Landing Zones
9,Connectivity,Management Group,Platform
10,Identity,Management Group,Platform
11,Management,Management Group,Platform
12,subcr-1,Subscription,Decommissioned
13,subcr-2,Subscription,Sandboxes
14,subcr-3,Subscription,Corp
15,subcr-4,Subscription,Online
16,subcr-5,Subscription,Connectivity
17,subcr-6,Subscription,Identity
18,subcr-7,Subscription,Management

Make your diagram animated and interactive

You can make your diagram animated and interactive by following these steps:

  1. File > Export as > URL
  2. Add p=ex& after the first ? in the URL.

For example, the URL should look like this:

https://viewer.diagrams.net/?p=ex&tags=%7B%7D&highlight=0000ff&layers=1&nav=1&title=MGs.drawio#R7Zxbc5s4FMc%2FjR%2BbAQkEPK7dJHWn3XbW6exMX3ZkkLFakDxCvvXTr7jFxrZi1k0Wg5lxYnR0QfqfHxqOBB7AUbx5FHgx%2F8wDEg2AEWwG8P0AAGAgQ32llm1uMU0X5pZQ0KCw7QwT%2BosUxqJiuKQBSSoFJeeRpIuq0eeMEV9WbFgIvq4Wm%2FGoetYFDsmRYeLj6Nj6Nw3kvBwG8nYZHwgN58WpXeDkGTEuCxcjSeY44Os9E7wfwJHgXOZH8WZEolS9Upe83oMm97ljgjB5osK3hIgv0x%2BpJsCI8FQ5Jis0AHZAk0WEt3%2FimKhU3k7Z7HBLxq7x42mcwOHy%2B0dn9PCRvIOFz%2FYrZqWfCMMsPcFf6TCA8Sj4clE0KEn8tF0UBT9jpoSKCTso9TXr%2Fjgo%2B5YNKcI%2BmStHEbHvvKoMidyWLioGN6Rx7ksah0qFiE7Vf%2FxrKUgqSkgYEVjVfNh15Z%2BsI8ldsgpV9fVcdXmyUOdWbawVzso2l3Eqm6kOVVEWkKBIpSjRKBrxiIusF3aaTNWEw0QK%2FpPssiDyXTKdqZxqFRhg4s58ZV9wymQ2VnuoPsadcsrIqPzZqsLoOc88zFOftFOpfCsiJNloIdnX8pHwmEixVUWKCpYD7goituU1nCfXO%2FqB4ea2%2BR74dmHDhc%2FC57Z3TKqDwoFlco%2FS16fW0lA7ZpKImAQUZ0PXsXkJwS9cED3WDWINnQOsTegec%2B20g2tbw%2FV74vM4pklCOVMuvRjimtdHD3RzQJezcjlJ2%2BiIZtNrB81IQ%2FMnzALKFCLGd4Vz0uPcYZyhZ57nuSWzs6Ph%2BWuE5YyLuAe5wyB7rn0eZKsdILsakCdqYp7yze9MySfn9p7bBu8nAKxwCx3rmFvUDm49DbcjLn4jsuuRvTJkLWieRxa0AlnL0CD7hUWUkR7azkBre955aGE7oDW182y2FE9XVG4vR7d6u9wz2xyzjuN05d7AAhpmx4ESo%2Be1E7wexmBtnmN1G2%2F7TPbEtp1Y00Q1wq92rH9Zul23ZDn1xTvzFK%2BT5TTxBV1IytkpUk9tbLwxr%2FtdentWAzRFNjpmdTabAf8VWc0GXz7HANAr3dPWmG5bEofpdtZydsEl7B6slvXYXgu2wKrOuZYHWsutbg8t5xZewu1utaxH9lqQPVzyajOyum2yHFnrEmT3V8t6aK8FWmRYnYFWtyWWQ2tfAu3xalmP7rWg63hOZ9DV7Yrl6KJL0K0umvXYXgu2nmd0BVtbtzOWY%2Btcgu3h2lkP7rWAa5qu2yS5Ry9ZnGayGNcKR0tSog2qjPhLsXp2IGHBH%2BmrKCo5jbj%2F82lOWW5%2BSB2ZF5pxJovXX8ysUhCSSdEgF3LOQ85wdL%2BzFoKn5V6WW3WML4VPXhhS%2BYKHxCIk8qWC1mkHChJhdQ9T7cl%2FcEZN5UH3lLfqKm83qjy8YeVRo8pbN6y806jydveUR3WVdxtVHt2w8l6jyju3q3z%2BFF5jyrvdU96pq7wmLPiflPduWHnQpPLlrwPcpPKwUeU7GMPadZVvNIZFHYxh3brKNxrDog7GsF5d5RuNYVH3YtjylY3zyjcaw6LuxbDlewfnlW80hkXdi2HLp%2BfPK99oDIu6F8Naddfn7TeKYVVy90tVWd7eD37B%2B38B#%7B%22pageId%22%3A%22UGUHswWqf16rUITyRAQM%22%7D

You can check it here

References

Moving Management Groups and Subscriptions

Managing your Azure resources efficiently often involves moving management groups and subscriptions. Here's a brief guide on how to do it:

Moving Management Groups

To move a management group, you need to have the necessary permissions. You must be an owner of the target parent management group and have Management Group Contributor role at the group you want to move.

Here's the step-by-step process:

  1. Navigate to the Azure portal.
  2. Go to Management groups.
  3. Select the management group you want to move.
  4. Click Details.
  5. Under Parent group, click Change.
  6. Choose the new parent group from the list and click Save.

Remember, moving a management group will also move all its child resources including other management groups and subscriptions.

Moving Subscriptions

You can move a subscription from one management group to another or within the same management group. To do this, you must have the Owner or Contributor role at the target management group and Owner role at the subscription level.

Follow these steps:

  1. Go to the Azure portal.
  2. Navigate to Management groups.
  3. Select the management group where the subscription currently resides.
  4. Click on Subscriptions.
  5. Find the subscription you want to move and select ..." (More options).
  6. Click Change parent.
  7. In the pop-up window, select the new parent management group and click Save.

Note

Moving subscriptions could affect the resources if there are policies or permissions applied at the management group level. It's important to understand the implications before making the move. Also, keep in mind that you cannot move the Root management group or rename it.

In conclusion, moving management groups and subscriptions allows for better organization and management of your Azure resources. However, it should be done carefully considering the impact on resources and compliance with assigned policies.

Management Groups

What are Management Groups?

Management Groups are a way to manage access, policies, and compliance for multiple subscriptions. They provide a way to manage access, policies, and compliance for multiple subscriptions. Management groups are containers that help you manage access, policy, and compliance for multiple subscriptions. You organize subscriptions into containers called "management groups" and apply your governance conditions to the management groups. All subscriptions within a management group automatically inherit the conditions applied to the management group.

Management Groups Hierarchy

The management group hierarchy is a level of management groups that represent the different levels of your organization. The hierarchy starts with a single root management group, which represents the Microsoft Entra ID tenant. The root management group is the highest level in the hierarchy. All other management groups are subgroups of the root management group.

Management group design considerations

When designing your management group hierarchy, consider the following:

  • How does your organization differentiate services that are managed or run by particular teams?

  • Are there any specific operations that need to be isolated due to business or regulatory compliance requirements?

  • Management groups can be utilized to consolidate policy and initiative assignments through Azure Policy.

  • A management group hierarchy can accommodate up to six nested levels. The tenant root level and the subscription level are not included in this count.

  • Any principal, be it a user or service principal, within a Microsoft Entra tenant has the authority to establish new management groups. This is due to the fact that Azure role-based access control (RBAC) authorization for managing group activities is not activated by default. For additional details, refer to the guide on safeguarding your resource hierarchy.

  • By default, all newly created subscriptions will be assigned to the tenant root management group.

Management group recommendations

  • Maintain a relatively flat management group hierarchy, ideally with three to four levels maximum. This practice minimizes managerial complexity and overhead.

  • Refrain from mirroring your organizational structure into a deeply nested management group hierarchy. Utilize management groups primarily for policy assignment rather than billing. This strategy aligns with the Azure landing zone conceptual architecture, which applies Azure policies to workloads that need similar security and compliance at the same management group level.

  • Establish management groups under your root-level group representing different types of workloads you will host. These groups should reflect the security, compliance, connectivity, and feature requirements of the workloads. By doing this, you can apply a set of Azure policies at the management group level for all workloads with similar needs.

  • Leverage resource tags for querying and horizontally traversing across the management group hierarchy. Resource tags, enforced or appended via Azure Policy, allow you to group resources for search purposes without relying on a complex management group hierarchy.

  • Set up a top-level sandbox management group. This allows users to immediately experiment with Azure and try out resources not yet permitted in production environments. The sandbox provides isolation from your development, testing, and production settings.

  • Create a platform management group beneath the root management group to support common platform policy and Azure role assignments. This ensures distinct policies can be applied to subscriptions used for your Azure foundation and centralizes billing for common resources in one foundational subscription set.

  • Minimize the number of Azure Policy assignments made at the root management group scope. This reduces the debugging of inherited policies in lower-level management groups.

  • Implement policies to enforce compliance requirements either at the management group or subscription scope to achieve policy-driven governance.

  • Ensure only privileged users have operational access to management groups in the tenant. Enable Azure RBAC authorization in the management group hierarchy settings to fine-tune user privileges. By default, all users are authorized to create their own management groups under the root management group.

  • Set up a default, dedicated management group for new subscriptions. This prevents any subscriptions from being placed under the root management group. This is particularly important if there are users eligible for Microsoft Developer Network (MSDN) or Visual Studio benefits and subscriptions. A sandbox management group could be a suitable candidate for this type of management group. For more information, see Setting - default management group.

  • Avoid creating management groups for production, testing, and development environments. If needed, separate these groups into different subscriptions within the same management group.

Management Group Structure in the Enterprise Scale Landing Zone

This is the common structure for the Management Groups in the Enterprise Scale Landing Zone:

    graph TD
        A[Root Management Group] --> B[Intermediary-Management-Group]
        B --> C[Decommissioned]
        B --> D[Landing Zones]
        B --> E[Platform]
        B --> F[Sandboxes]
        D --> G[Corp]
        D --> H[Online]
        E --> I[Connectivity]
        E --> J[Identity]
        E --> K[Management]
  1. Root Management Group
    • Intermediary-Management-Group
      • Decommissioned: This could be where resources that are being phased out or decommissioned are managed.
      • Sandboxes: This could be an area where developers can test and experiment without affecting production systems.
      • Landing Zones
        • Corp: This could represent corporate resources or applications.
        • Online: This could represent online or customer-facing applications.
      • Platform
        • Connectivity: This could manage resources related to network connectivity.
        • Identity: This could manage resources related to identity and access management.
        • Management: This could manage resources related to overall platform management.

This structure allows for clear segmentation of resources based on their purpose and lifecycle. For example, decommissioned resources are separated from active ones, like Sandbox, and resources within the 'Platform' are further categorized based on their function (Connectivity, Identity, Management). The 'Landing Zones' group appears to separate resources based on their use case or environment (Corp, Online).

The exact interpretation would depend on the specific context and conventions of your organization.

Bad Examples

Example 1: Deeply Nested Hierarchy

graph TD
    A[Root Management Group] --> B[Group 1]
    B --> C[Group 2]
    C --> D[Group 3]
    D --> E[Group 4]
    E --> F[Group 5]
    F --> G[Group 6]

Why it's bad: This hierarchy is too deep. It becomes difficult to manage and increases complexity. Azure supports up to six levels of nested management groups but it's recommended to keep the hierarchy as flat as possible for simplicity.

Example 2: Unorganized Structure

graph TD
    A[Root Management Group] --> B[Group 1]
    A --> C[Group 2]
    B --> D[Group 3]
    C --> E[Group 4]
    D --> F[Group 5]
    E --> G[Group 6]

Why it's bad: The structure is not well-organized and doesn't follow a logical grouping or hierarchy. This can lead to confusion and difficulty in managing resources and policies.

Example 3: Single Level Hierarchy

graph TD
    A[Root Management Group] --> B[Group 1]
    A --> C[Group 2]
    A --> D[Group 3]
    A --> E[Group 4]
    A --> F[Group 5]
    A --> G[Group 6]

Why it's bad: Although this structure is simple, it lacks the ability to group related subscriptions together under a common management group. This makes it harder to apply consistent policies across related subscriptions.

Example 4: Environment-Based Hierarchy


graph TD
    A[Root Management Group] --> B[Production Management Group]
    A[Root Management Group] --> C[Development Management Group]
    A[Root Management Group] --> D[Testing Management Group]

Why it's bad: This structure separates environments into different management groups, which can lead to duplication of policies and increased complexity. It's better to use subscriptions within the same management group to separate environments and apply policies accordingly.

Good examples

    graph TD
        A[Root Management Group] --> B[Intermediary-Management-Group]
        B --> C[Decommissioned]
        B --> D[Landing Zones]
        B --> E[Platform]
        B --> F[Sandboxes]
        D --> G[Corp]
        D --> H[Online]
        E --> I[Connectivity]
        E --> J[Identity]
        E --> K[Management]

😄

References

  • https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/landing-zone/design-area/resource-org-management-groups
  • https://learn.microsoft.com/en-us/azure/governance/management-groups/overview

How to create assigment Reports for Azure RBAC

Role-Based Access Control (RBAC) is a key feature of Azure that allows you to manage access to Azure resources. With RBAC, you can grant permissions to users, groups, and applications at a certain scope, such as a subscription, resource group, or resource. RBAC uses role assignments to determine what actions a user, group, or application can perform on a resource.

In this article, we will show you how to create reports for role assignments in Azure using PowerShell and the ImportExcel module. We will generate separate Excel files for role assignments at the subscription and management group levels, including information such as the role, principal, scope, and whether the assignment is inherited.

Role assignment report in Excel

This is the PowerShell script that generates the role assignment reports:

# Parameters setup
param (
    [Parameter(Mandatory=$false)]
    [string]$SubscriptionId,

    [Parameter(Mandatory=$false)]
    [string]$ManagementGroupName,

    [Parameter(Mandatory=$false)]
    [bool]$GetSubscriptions = $false,

    [Parameter(Mandatory=$false)]
    [bool]$GetManagementGroups = $true
)


# Install the ImportExcel module if not already installed
if (!(Get-Module -ListAvailable -Name ImportExcel)) {
    Install-Module -Name ImportExcel -Scope CurrentUser
}

# Define the path to your Excel file for Managing Group role assignments
$managementGroupPath = ".\AzRoleAssignmentMg.xlsx"
# Define the path to your Excel file for Subscription role assignments
$subscriptionPath = ".\AzRoleAssignmentSub.xlsx"

# Initialize an empty array to hold all role assignments
$subscriptionRoleAssignments = @()
$managementGroupRoleAssignments = @()

if ($GetManagementGroups) {
    # Check if ManagementGroupName is provided
    if ($ManagementGroupName) {
        # Get role assignments for the specified management group
        $roleAssignments = Get-AzRoleAssignment -Scope "/providers/Microsoft.Management/managementGroups/$ManagementGroupName"

        # Add these role assignments to the management group role assignments array
        $managementGroupRoleAssignments += $roleAssignments

        # Add 'GroupName' and 'IsInherited' properties to each role assignment object
        $roleAssignments | ForEach-Object {
            $_ | Add-Member -NotePropertyName 'GroupDisplayName' -NotePropertyValue (Get-AzManagementGroup -GroupName $ManagementGroupName).DisplayName
            $_ | Add-Member -NotePropertyName 'GroupName' -NotePropertyValue $ManagementGroupName
            # If the Scope of the role assignment is equal to the Id of the management group,
            # then the role assignment is not inherited; otherwise, it is inherited.
            if ($_.Scope -eq "/providers/Microsoft.Management/managementGroups/$ManagementGroupName") {
                $_ | Add-Member -NotePropertyName 'IsInherited' -NotePropertyValue $false
            } else {
                $_ | Add-Member -NotePropertyName 'IsInherited' -NotePropertyValue $true
            }
        }

        # Export the role assignments to a new sheet in the Excel file
        $roleAssignments | Export-Excel -Path $managementGroupPath -WorksheetName (Get-AzManagementGroup -GroupName $ManagementGroupName).DisplayName -AutoSize -AutoFilter
    } else {
        # Get all management groups
        $managementGroups = Get-AzManagementGroup
        # Loop through each management group
        foreach ($mg in $managementGroups) {
            # Get role assignments for the current management group
            $roleAssignments = Get-AzRoleAssignment -Scope "/providers/Microsoft.Management/managementGroups/$($mg.Name)"

            # Add these role assignments to the management group role assignments array
            $managementGroupRoleAssignments += $roleAssignments

            # Add 'GroupName' and 'IsInherited' properties to each role assignment object
            $roleAssignments | ForEach-Object {
                $_ | Add-Member -NotePropertyName 'GroupDisplayName' -NotePropertyValue $mg.DisplayName
                $_ | Add-Member -NotePropertyName 'GroupName' -NotePropertyValue $mg.Name
                # If the Scope of the role assignment is equal to the Id of the management group,
                # then the role assignment is not inherited; otherwise, it is inherited.
                if ($_.Scope -eq $mg.Id) {
                    $_ | Add-Member -NotePropertyName 'IsInherited' -NotePropertyValue $false
                } else {
                    $_ | Add-Member -NotePropertyName 'IsInherited' -NotePropertyValue $true
                }
            }

            # Export the role assignments to a new sheet in the Excel file
            $roleAssignments | Export-Excel -Path $managementGroupPath -WorksheetName $mg.DisplayName -AutoSize -AutoFilter
        }
}

if ($GetSubscriptions) {   
    # Check if SubscriptionId is provided
    if ($SubscriptionId) {
        # Get role assignments for the specified subscription
        $roleAssignments = Get-AzRoleAssignment -Scope "/subscriptions/$SubscriptionId"

        # Add these role assignments to the subscription role assignments array
        $subscriptionRoleAssignments += $roleAssignments

        # Add 'SubscriptionName' and 'IsInherited' properties to each role assignment object
        $roleAssignments | ForEach-Object { 
            $_ | Add-Member -NotePropertyName 'SubscriptionName' -NotePropertyValue (Get-AzSubscription -SubscriptionId $SubscriptionId).Name 
            $_ | Add-Member -NotePropertyName 'IsInherited' -NotePropertyValue $false
        }

        # Export the role assignments to a new sheet in the Excel file
        $roleAssignments | Export-Excel -Path $subscriptionPath -WorksheetName (Get-AzSubscription -SubscriptionId $SubscriptionId).Name -AutoSize -AutoFilter
    } else {
        # Get all subscriptions
        $subscriptions = Get-AzSubscription

        # Loop through each subscription
        foreach ($sub in $subscriptions) {
            # Get role assignments for the current subscription
            $roleAssignments = Get-AzRoleAssignment -Scope "/subscriptions/$($sub.SubscriptionId)"

            # Add these role assignments to the subscription role assignments array
            $subscriptionRoleAssignments += $roleAssignments

            # Add 'SubscriptionName' and 'IsInherited' properties to each role assignment object
            $roleAssignments | ForEach-Object { 
                $_ | Add-Member -NotePropertyName 'SubscriptionName' -NotePropertyValue $sub.Name
                 # If the Scope of the role assignment is equal to the subscription Id,
                 # then the role assignment is not inherited; otherwise, it is inherited.
                if ($_.Scope -eq "/subscriptions/$($sub.Id)") {
                    $_ | Add-Member -NotePropertyName 'IsInherited' -NotePropertyValue $false
                } else {
                    $_ | Add-Member -NotePropertyName 'IsInherited' -NotePropertyValue $true                }

            }

            # Export the role assignments to a new sheet in the Excel file
            $roleAssignments | Export-Excel -Path $subscriptionPath -WorksheetName $sub.Name -AutoSize -AutoFilter
        }
    }
}

This script takes the following parameters:

  • GetSubscriptions: A switch parameter that specifies whether to generate reports for subscriptions. The default value is $false.
  • GetManagementGroups: A switch parameter that specifies whether to generate reports for management groups. The default value is $true.
  • SubscriptionId: The ID of the subscription for which you want to generate the report. If this parameter is not provided, the script will generate reports for all subscriptions.
  • ManagementGroupName: The name of the management group for which you want to generate the report. If this parameter is not provided, the script will generate reports for all management groups.

Role definition report in Excel 1

You can also generate a report for role definitions in Azure using the following PowerShell script:

param(
    [Parameter(Mandatory=$false)]
    [ValidateSet('Console', 'Excel')]
    [string]$OutputType = 'Console',

    [Parameter(Mandatory=$false)]
    [string]$ExcelFilePath = ".\AzRoleDefinition.xlsx"
)

# Install the ImportExcel module if not already installed
if (!(Get-Module -ListAvailable -Name ImportExcel)) {
    Install-Module -Name ImportExcel -Scope CurrentUser
}

# Install the  AzureRM module if not already installed
if (!(Get-Module -ListAvailable -Name  Az)) {
    Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
    Install-Module -Name  Az -Scope CurrentUser
}

# Get all role definitions
$roleDefinitions = Get-AzRoleDefinition | ForEach-Object {
    # Create a custom object with ordered properties
    $customObject = New-Object PSObject -Property @{
        Name = $_.Name
        Id = $_.Id
        IsCustom = $_.IsCustom
        Description = $_.Description
        Actions = ($_.Actions -join ', ').Replace(',', ",`n")
        NotActions = ($_.NotActions -join ', ').Replace(',', ",`n")
        DataActions = ($_.DataActions -join ', ').Replace(',', ",`n")
        NotDataActions = ($_.NotDataActions -join ', ').Replace(',', ",`n")
        AssignableScopes = ($_.AssignableScopes -join ', ').Replace(',', ",`n")
    } | Select-Object Name, Id, IsCustom, Description, Actions, NotActions, DataActions, NotDataActions, AssignableScopes

    return $customObject
}

if ($OutputType -eq 'Console') {
    # Output to console
    $roleDefinitions | Format-Table -AutoSize
} else {
    # Export to Excel
    $roleDefinitions | Export-Excel -Path $ExcelFilePath -WorksheetName 'Role Definitions' -AutoSize -AutoFilter    
}

This script takes the following parameters:

  • OutputType: A string parameter that specifies the output type. The default value is 'Console'. You can also specify 'Excel' to export the report to an Excel file.
  • ExcelFilePath: The path to the Excel file where you want to export the report. The default value is ".\AzRoleDefinition.xlsx".

In the Excel report, you will see the following columns for each role definition: Name, Id, IsCustom, Description, Actions, NotActions, DataActions, NotDataActions, and AssignableScopes.

Role definition report in Excel 1

In this report we generate a report for role definitions in Azure with three columns: Name, JsonDefinition and IsCustom

You can also generate a report for role definitions in Azure using the following PowerShell script:

```powershell param( [Parameter(Mandatory=$false)] [ValidateSet('Console', 'Excel')] [string]$OutputType = 'Console',

[Parameter(Mandatory=$false)]
[string]$ExcelFilePath = ".\AzRoleDefinition.xlsx"

)

Install the ImportExcel module if not already installed

if (!(Get-Module -ListAvailable -Name ImportExcel)) { Install-Module -Name ImportExcel -Scope CurrentUser }

Install the AzureRM module if not already installed

if (!(Get-Module -ListAvailable -Name Az)) { Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser Install-Module -Name Az -Scope CurrentUser }

Get all role definitions

$roleDefinitions = Get-AzRoleDefinition | ForEach-Object { # Create a custom object with ordered properties $customObject = New-Object PSObject -Property @{ Name = $.Name JsonDefinition = ($ | ConvertTo-Json -Depth 10 -Compress) IsCustom = $_.IsCustom } | Select-Object Name, JsonDefinition, IsCustom

return $customObject

}

if ($OutputType -eq 'Console') { # Output to console $roleDefinitions | Format-Table -AutoSize } else { # Export to Excel $roleDefinitions | Export-Excel -Path $ExcelFilePath -WorksheetName 'Role Definitions' -AutoSize -AutoFilter
}