pulumi / pulumi-azure-native

Azure Native Provider
Apache License 2.0
128 stars 35 forks source link

WebAppSourceControl tries to look up a "User" when a "Service Principal" is logged in. #3602

Open erik-toger opened 1 month ago

erik-toger commented 1 month ago

What happened?

I get:

azure-native:web:WebAppSourceControl etoger-lp-backend-sourceControl creating (1s) error: Code="NotFound" Message="Cannot find User with name id-for-my-service-principal."

The problem is that it is trying to find a "User" when it should be looking up a "Service Principal". The Id used is actually the Object Id for the Enterprise Application for the service principal, if that detail matters.

Or this is a bug with: https://github.com/pulumi/pulumi-azure-native ???

I have a:

var sourceControl = new WebAppSourceControl(sourceControlName, new WebAppSourceControlArgs
            {
                Name = webApp.Name,
                ResourceGroupName = _resourceGroup.Name,
                RepoUrl = gitHubRepoUrl ?? "",
                Branch = "main",
                GitHubActionConfiguration =  new GitHubActionConfigurationArgs{       
                },
                IsGitHubAction = true
            });

And in Github actions I run:

      - name: Pulumi up
        uses: pulumi/actions@v6
        with:
          command: up
          stack-name: dev
          work-dir: Deploy
        env:
          ARM_USE_OIDC: true
          PULUMI_ACCESS_TOKEN: ${{ secrets.PULUMI_ACCESS_TOKEN }}
          ARM_CLIENT_ID: ${{ secrets.AZURE_SP_CLIENT_ID }}
          ARM_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
          ARM_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

Example

 var webApp = new WebApp(webAppName, new WebAppArgs
            {
                ResourceGroupName = _resourceGroup.Name,
                Location = location ?? "",
                ServerFarmId = appServicePlanId,
                Name = webAppName,
                Kind = "app",
                Identity = new ManagedServiceIdentityArgs
                {
                    Type = Pulumi.AzureNative.Web.ManagedServiceIdentityType.SystemAssigned
                },
                SiteConfig = new SiteConfigArgs
                {
                    Cors = cors,
                },
            });

            var gitHubRepoUrl = _config.Get("gitHubRepoUrl");
            var sourceControlName = $"{_prefix}-sourceControl";

            var sourceControl = new WebAppSourceControl(sourceControlName, new WebAppSourceControlArgs
            {
                Name = webApp.Name,
                ResourceGroupName = _resourceGroup.Name,
                RepoUrl = gitHubRepoUrl ?? "",
                Branch = "main",
                GitHubActionConfiguration =  new GitHubActionConfigurationArgs{       
                },
                IsGitHubAction = true
            });

Github action workflow:

name: Deploy and Run Workflows

on:
  workflow_dispatch:

permissions:
  id-token: write
  contents: read

jobs:
  pulumi:
    name: Login to Azure and Pulumi up
    runs-on: ubuntu-latest

    steps:
      - name: Checkout repository
        uses: actions/checkout@v2

      - name: Install dotnet
        uses: actions/setup-dotnet@v3
        with:
          dotnet-version: 8.0.x

      - name: Az CLI login
        uses: azure/login@v2
        with:
          client-id: ${{ secrets.AZURE_SP_CLIENT_ID }}
          tenant-id: ${{ secrets.AZURE_TENANT_ID }}
          subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

      - name: Pulumi refresh
        uses: pulumi/actions@v6
        with:
          command: refresh
          stack-name: dev
          work-dir: Deploy
        env:
          ARM_USE_OIDC: true
          PULUMI_ACCESS_TOKEN: ${{ secrets.PULUMI_ACCESS_TOKEN }}
          ARM_CLIENT_ID: ${{ secrets.AZURE_SP_CLIENT_ID }}
          ARM_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
          ARM_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

      - name: Pulumi up
        uses: pulumi/actions@v6
        with:
          command: up
          stack-name: dev
          work-dir: Deploy
          refresh: true
        env:
          ARM_USE_OIDC: true
          PULUMI_ACCESS_TOKEN: ${{ secrets.PULUMI_ACCESS_TOKEN }}
          ARM_CLIENT_ID: ${{ secrets.AZURE_SP_CLIENT_ID }}
          ARM_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
          ARM_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

  get_frontend_deploy_token:
    needs: pulumi
    runs-on: ubuntu-latest
    outputs:
      api_token: ${{ steps.get_swa_secret.outputs.api_token }} # Define output for the job
    steps:
      - name: Az CLI login
        uses: azure/login@v2
        with:
          client-id: ${{ secrets.AZURE_SP_CLIENT_ID }}
          tenant-id: ${{ secrets.AZURE_TENANT_ID }}
          subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

      - name: Get SWA API Token
        id: get_swa_secret
        run: |
          rgName="etoger-lp-RG"
          siteName="etoger-lp-frontend-swa"
          api_token=$(az staticwebapp secrets list --name $siteName --resource-group $rgName --query "properties.apiKey" -o tsv)
          echo "api_token=${api_token}" >> $GITHUB_OUTPUT

  deploy_frontend:
    needs: get_frontend_deploy_token
    name: Deploy Frontend
    uses: ./.github/workflows/frontend-swa.yml
    secrets:
      AZURE_SWA_FRONTEND_API_TOKEN: ${{ needs.get_frontend_deploy_token.outputs.api_token }}

  get_backend_client_id:
    needs: pulumi
    name: Get backend client id
    runs-on: ubuntu-latest
    outputs:
      client_id: ${{ steps.get_client_id.outputs.client_id }}
    steps:
      - name: Az CLI login
        uses: azure/login@v2
        with:
          client-id: ${{ secrets.AZURE_SP_CLIENT_ID }}
          tenant-id: ${{ secrets.AZURE_TENANT_ID }}
          subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

      - name: Get Backend Client ID from Azure AD App Registration
        id: get_client_id
        run: |
          app_id=$(az ad app list --display-name "etoger-lp-backend-application" --query "[0].appId" -o tsv)
          echo "client_id=${app_id}" >> $GITHUB_OUTPUT  # Set output for the job

  deploy_backend:
    needs: get_backend_client_id
    name: Deploy Backend
    uses: ./.github/workflows/backend.yml
    secrets:
      AZURE_BACKEND_CLIENTID: ${{ needs.get_backend_client_id.outputs.client_id }}
      AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
      AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

  find_swa:
    runs-on: ubuntu-latest
    needs: [deploy_frontend, deploy_backend]
    name: Find SWA url
    steps:
      - name: Az CLI login
        uses: azure/login@v2
        with:
          client-id: ${{ secrets.AZURE_SP_CLIENT_ID }}
          tenant-id: ${{ secrets.AZURE_TENANT_ID }}
          subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
      - name: Get the url
        run: az staticwebapp list --resource-group "etoger-lp-RG" --query "[].{Name:name,URL:defaultHostname}" --output table

Output of pulumi about

running 'dotnet build -nologo .' Determining projects to restore...

All projects are up-to-date for restore.

Build succeeded.

0 Warning(s)
0 Error(s)

Time Elapsed 00:00:05.77

'dotnet build -nologo .' completed successfully CLI Version 3.133.0 Go Version go1.23.1 Go Compiler gc

Plugins KIND NAME VERSION resource azure 6.0.0 resource azure-native 2.62.0 resource azuread 5.53.4 resource command 1.0.1 language dotnet unknown resource github 6.3.0

Host OS Microsoft Windows 11 Pro Version 10.0.22631 Build 22631 Arch x86_64

This project is written in dotnet: executable='C:\Program Files\dotnet\dotnet.exe' version='8.0.401'

Current Stack: erik-toger/learn-pulumi/dev

TYPE URN pulumi:pulumi:Stack urn:pulumi:dev::learn-pulumi::pulumi:pulumi:Stack::learn-pulumi-dev pulumi:providers:github urn:pulumi:dev::learn-pulumi::pulumi:providers:github::etoger-lp-gitHub-provider pulumi:providers:azuread urn:pulumi:dev::learn-pulumi::pulumi:providers:azuread::default_5_53_4 pulumi:providers:azure-native urn:pulumi:dev::learn-pulumi::pulumi:providers:azure-native::default_2_62_0 azuread:index/application:Application urn:pulumi:dev::learn-pulumi::azuread:index/application:Application::etoger-lp-backend-application azure-native:resources:ResourceGroup urn:pulumi:dev::learn-pulumi::azure-native:resources:ResourceGroup::etoger-lp-RG github:index/actionsSecret:ActionsSecret urn:pulumi:dev::learn-pulumi::github:index/actionsSecret:ActionsSecret::etoger-lp-backend-clientIdSecret azuread:index/servicePrincipal:ServicePrincipal urn:pulumi:dev::learn-pulumi::azuread:index/servicePrincipal:ServicePrincipal::etoger-lp-backend-servicePrincipal azuread:index/applicationFederatedIdentityCredential:ApplicationFederatedIdentityCredential urn:pulumi:dev::learn-pulumi::azuread:index/applicationFederatedIdentityCredential:ApplicationFederatedIdentityCredential::etoger-lp-backend-federatedCredential azure-native:authorization:RoleAssignment urn:pulumi:dev::learn-pulumi::azure-native:authorization:RoleAssignment::etoger-lp-backend-servicePrincipal-RoleAssignment azure-native:web:StaticSite urn:pulumi:dev::learn-pulumi::azure-native:web:StaticSite::etoger-lp-frontend-swa azure-native:web:AppServicePlan urn:pulumi:dev::learn-pulumi::azure-native:web:AppServicePlan::etoger-lp-backend-serviceplan azuread:index/servicePrincipalPassword:ServicePrincipalPassword urn:pulumi:dev::learn-pulumi::azuread:index/servicePrincipalPassword:ServicePrincipalPassword::etoger-lp-backend-servicePrincipalPassword github:index/actionsSecret:ActionsSecret urn:pulumi:dev::learn-pulumi::github:index/actionsSecret:ActionsSecret::etoger-lp-frontend-gitHub-secret azure-native:web:WebApp urn:pulumi:dev::learn-pulumi::azure-native:web:WebApp::etoger-lp-backend-WebApp github:index/actionsVariable:ActionsVariable urn:pulumi:dev::learn-pulumi::github:index/actionsVariable:ActionsVariable::etoger-lp-backend-vite-backend-api-url azure-native:documentdb:DatabaseAccount urn:pulumi:dev::learn-pulumi::azure-native:documentdb:DatabaseAccount::etoger-lp-database-account

Found no pending operations associated with dev

Backend
Name pulumi.com URL https://app.pulumi.com/erik-toger User erik-toger Organizations erik-toger Token type personal

Dependencies: NAME VERSION Pulumi 3.67.1 Pulumi.Azure 6.0.0 Pulumi.AzureAD 5.53.4 Pulumi.AzureNative 2.62.0 Pulumi.Command 1.0.1 Pulumi.Github 6.3.0

Pulumi locates its logs in C:\Users\etoger\AppData\Local\Temp by default

Additional context

It works fine from command line since then it is my user that is the caller. But in the Github actions pipeline, then it is the Service Principal that is logged in to Azure and Pulumi. And in the pipeline it managed to create 15 other resources before failing:

    pulumi:pulumi:Stack (learn-pulumi-dev):
      error: update failed

  Resources:
      + 15 created

Contributing

Vote on this issue by adding a 👍 reaction. To contribute a fix for this issue, leave a comment (and link to your pull request, if you've opened one already).

justinvp commented 1 month ago

This looks specific to Azure Native, so transferring the issue to that repo.

thomas11 commented 1 month ago

Hi @erik-toger, I haven't worked with WebAppSourceControl myself, so it's surprising to me that it looks for a user while none is configured in its creation (or can even be configured). What user is it looking for, to authenticate where?

There's one issue on GitHub that suggests it might have to do with the shape of the repo URL. Maybe something worth looking into.

erik-toger commented 1 month ago

Hello @thomas11 I don't have any references to tree/master or tree/main in my code that the issue that you linked to is referring to.

What user is it looking for, to authenticate where?

The id it is using is the id to my Service Principal, that is logged in both for azure and for pulumi in the pipeline. So I thought it was just some error that "az ad user" was used when "az ad sp" should be used instead. But I'm not sure what is so special about "WebAppSourceControl". Because it manage to create the static web app that is using a github personal access token. So authorizing to github seems to work jus fine.

Im new to pulumi, so It is very likely that I have misunderstood how I should use it. But it works fine from command line.

thomas11 commented 1 month ago

I'm afraid there might be an issue on the Azure side here. See this (sadly unresolved) issue, for instance: WebApp | Service Principal cannot createOrUpdateSourceControl.

Since the authentication of the WebAppSourceControl is not configurable at all, I don't think we can do much on the Pulumi side. The fact that your other resources work fine shows that your setup is correct.

erik-toger commented 1 month ago

Thank you for digging deeper into it. Are you using the azure-sdk-for-js under the hood? In case I want to open a issue over at Azure instead?

erik-toger commented 1 month ago

It is definitely a Azure bug since I get the same error message if run this in my github actions pipeline:

 - name: Create source control directly
   run: "az webapp deployment source config --name <web-app-name> --resource-group <RG-name> --repo-url <repo-url> --branch main --github-action true"

So I opened a issue: az webapp deployment source looks for user even if it is called by a Service Prinicpal

thomas11 commented 1 month ago

Nice, at least we know now where the problem is. Sorry we couldn't help you, though. I'll leave this issue open to track the Azure issue.