{
  "id": 6334568,
  "title": "Migrating CI/CD from Azure DevOps to GitHub Actions with Azure OIDC and ACR",
  "url": "https://urgent.news/2026/09/08/migrating-ci-cd-from-azure-devops-to-github-actions-with-azure-oidc",
  "topic": "tech",
  "section": "Tech",
  "published": "2026-09-08T21:25:06.000Z",
  "source": {
    "name": "Dev.to",
    "slug": "dev-to",
    "url": "https://dev.to/desmond_goldsmith/migrating-cicd-from-azure-devops-to-github-actions-with-azure-oidc-and-acr-32f3"
  },
  "original_language": "en",
  "account": "Introduction\nA report is being written detailing the process of migrating Continuous Integration/Continuous Deployment (CI/CD) pipelines from Azure DevOps to GitHub Actions using Azure OpenID Connect (OIDC) and Azure Container Registry (ACR).\n\nProject Repository\nThe source code for the practice project is available at the following GitHub URL. The main objective of this exercise was to build a Go application, set up a GitHub Actions pipeline, authenticate securely to Azure, build a Docker image, and push it to Azure Container Registry.\n\nPipeline Goals\nThe goal was to create a workflow that could:\n1. Run when a Pull Request is created\n2. Build and test the Go application\n3. Build a Docker image\n4. Authenticate to Azure without using a client secret\n5. Push the image to Azure Container Registry (ACR)\n\nWorkflow Overview\nThe final flow of the pipeline is as follows:\nPull Request → GitHub Actions → Go Build & Test → Docker Build → GitHub OIDC → Microsoft Entra ID → Azure Container Registry → Docker Image\n\nPractice Project\nA small Go REST API project was used for the exercise. The application's main focus was to be able to:\n1. Build successfully with Go\n2. Run inside Docker\n3. Expose an HTTP endpoint\n\nVerification of the application was done locally using `go run` and `curl` to test its health endpoint. The Docker image was also built locally and verified to ensure the container worked properly.\n\nGitHub Actions Pipeline\nA workflow file named `.github/workflows/ci-cd.yml` was created for the pipeline. The pipeline was intentionally kept simple and triggered by a Pull Request. The jobs section specifies the following steps:\n1. Checkout code using `actions/checkout@v4`\n2. Set up Go using `actions/setup-go@v5`\n3. Download dependencies with `go mod download`\n4. Build the Go application with `go build -v ./...`\n5. Run Go tests using `go test ./...`\n6. Build the Docker image with `docker build -t go-rest-api:1.0 .`\n\nPull Request Trigger\nThe pipeline is triggered by a Pull Request, which allows for validating changes before merging them into the main branch. A test branch named `test-branch` was created and pushed to initiate the workflow. The workflow then automatically started and passed the GitHub Actions check.\n\nAzure Preparation\nAn existing Azure Container Registry (ACR) with the name `dessydevopsacr` and login server `dessydevopsacr.azurecr.io` was prepared for this exercise. The goal was to allow GitHub Actions to push Docker images into this registry without using a client secret.\n\nAuthentication Method\nInstead of using the traditional approach of GitHub Actions → Client ID + Client Secret → Azure, OIDC was chosen for authentication. This method eliminates the need for a long-lived secret to be stored and managed. The authentication flow became GitHub Actions → OIDC token → Microsoft Entra ID → Azure.\n\nAzure App Registration\nIn the Azure Portal, a new app registration was created under Microsoft Entra ID with the following details:\n- Application (client) ID\n- Object ID\n- Directory (tenant) ID\n\nThese identifiers were provided by Azure and serve as important pieces of information for the authentication process. For a public article, it is recommended to replace these real IDs with placeholders such as `AZURE_CLIENT_ID`, `AZURE_TENANT_ID`, and `AZURE_SUBSCRIPTION_ID`.\n\nAvoiding Client Secrets\nCreate a client secret inside the application registration was avoided in this exercise. Instead, the application has:\n1. No client secrets (federated credentials)\n2. 1 federated credential, which allows GitHub Actions to authenticate without storing an Azure password/secret.\n\nCreating the Federated Credential\nInside the app registration, a federated credential was created using GitHub Actions deploying Azure resources. This step is crucial for GitHub Actions to authenticate securely with Azure without the need for a client secret.",
  "summary": "Introduction As part of learning and preparing for a migration from Azure DevOps pipelines to GitHub Actions , I decided to build a small practice project before working with a real application. Project repository: github url The goal for this exercise was straightforward: Build a Go application, create a GitHub Actions pipeline, authenticate securely to Azure, build a Docker image, and push it…",
  "key_points": [],
  "editors_take": null,
  "illustration": null,
  "coverage": {
    "outlets": 1,
    "also_reported_by": []
  },
  "ai_generated": true,
  "disclaimer": "Summaries, key points and the editor’s take are written by software from other outlets’ reporting and may contain errors — always check the linked original."
}