diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml index 96a8f48..954600d 100644 --- a/.github/workflows/deploy.yaml +++ b/.github/workflows/deploy.yaml @@ -11,54 +11,38 @@ permissions: jobs: deploy-bicep: - runs-on: ubuntu-latest name: Deploy Bicep + runs-on: ubuntu-latest + steps: - uses: actions/checkout@v3 - - uses: azure/login@v1 - name: Login to Azure + - name: Login to Azure + uses: azure/login@v1 with: client-id: ${{ secrets.AZURE_CLIENT_ID }} tenant-id: ${{ secrets.AZURE_TENANT_ID }} subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} enable-AzPSSession: true - # Why on earth can't I just deploy the bicep file? - - uses: azure/bicep-build-action@v1.0.0 - name: Bicep Build - with: - bicepFilePath: infrastructure/Cluster.bicep - outputFilePath: infrastructure/Cluster.json - - - id: name - shell: pwsh - run: '"name=aks-$(Get-Date -f yyyyMMddThhmmss)" >> $Env:GITHUB_OUTPUT' - - - uses: azure/arm-deploy@v1 - name: deploy - timeout-minutes: 240 - with: - template: infrastructure/Cluster.json - subscriptionId: ${{ secrets.AZURE_SUBSCRIPTION }} - resourceGroupName: ${{ secrets.AZURE_RG }} - parameters: adminId=${{ secrets.ADMIN_GROUP_ID }} - deploymentName: ${{ steps.name.outputs.name }} - - - id: deploy-flux - shell: pwsh - run: | - #! Get the cluster credentials - Get-AzAksCluster -ResourceGroupName $Env:RESOURCE_GROUP | - Import-AzAksCredential -Force - #! Update the client ID from the deployment output - $kustomize = Get-Content "clusters/poschode/flux/kustomization.ps1" - $kustomize = $kustomize -replace "azure.workload.identity/client-id: .*$", "azure.workload.identity/client-id: ${{ steps.deploy.outputs.fluxIdClientId }}" - # TODO: commit this file to the repo _before_ running flux - $kustomize | Set-Content "clusters/poschode/flux/kustomization.ps1" - #! Bootstrap Flux - ./infrastructure/Install-Flux.ps1 + - name: Azure Resource Group Deployment + uses: azure/powershell@v1 env: + SUBSCRIPTION: ${{ secrets.AZURE_SUBSCRIPTION }} + RESOURCEGROUP: ${{ secrets.AZURE_RG }} + ADMINS: ${{ secrets.ADMIN_GROUP_ID }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - RESOURCE_GROUP: ${{ secrets.AZURE_RG }} - + with: + azPSVersion: "latest" + inlineScript: | + $Results = New-AzResourceGroupDeployment -Name "aks-$(Get-Date -f yyyyMMddThhmmss)" -ResourceGroupName $Env:RESOURCEGROUP -TemplateFile ./infrastructure/Cluster.bicep -TemplateParameterObject @{ adminId = $Env:ADMINS } + $Results | Out-Host + #! Get the cluster credentials + Get-AzAksCluster -ResourceGroupName $Env:RESOURCEGROUP | Import-AzAksCredential -Force + #! Update the client ID from the deployment output + $kustomize = Get-Content "./clusters/poshcode/flux-system/kustomization.yaml" + $kustomize = $kustomize -replace "azure.workload.identity/client-id: .*$", "azure.workload.identity/client-id: $($Results.Outputs.fluxIdClientId)" + # TODO: commit this file to the repo _before_ running flux + $kustomize | Set-Content "./clusters/poshcode/flux-system/kustomization.yaml" + #! Bootstrap Flux + ./Initialize-Flux.ps1 diff --git a/Initialize-AuthApplication.ps1 b/Initialize-AuthApplication.ps1 new file mode 100644 index 0000000..389097a --- /dev/null +++ b/Initialize-AuthApplication.ps1 @@ -0,0 +1,67 @@ +<# + .SYNOPSIS + Prepares an Azure subscription, resource group, and service account and puts secrets into a GitHub repo. + .DESCRIPTION + Creates a new Azure AD application and service principal, and grants it access to a resource group. + Also creates a new federated identity credential for the service principal, and sets the secrets + for the repo workflows. +#> +[CmdletBinding()] +param( + # The identifier URIs to use. E.g. "https://auth.poshcode.com" + [string[]]$IdentifierUris = "https://auth.poshcode.com", + + # The service name to use. E.g. "poshcode-auth" + [string]$DisplayName = "poshcode-auth", + + # The repo to set secrets for. E.g. "PoshCode/cluster" + [string]$repo = "PoshCode/cluster", + + # The name of the secret to create. E.g. "azuread" + $Name = "azuread", + + # The namespace to create the secret in. E.g. "traefik" + $Namespace = "traefik", + + # The path to the secret file to create. E.g. "system/config/secret.yaml" + $Path = "system/config/secret.yaml" +) + +Push-Location $PSScriptRoot -StackName Initialize-AuthApplication + +filter global:ToBase64 { + [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($_)) +} +filter global:FromBase64 { + [Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($_)) +} + +$global:app = (Get-AzADApplication -DisplayName $DisplayName) ?? + (New-AzADApplication -DisplayName $DisplayName -IdentifierUris $IdentifierUris -ReplyUrls "$IdentifierUris/_oauth") + +$Secret = New-AzADAppCredential -ObjectId $App.Id -PasswordCredentials @{} + +$Secret = @" +apiVersion: v1 +kind: Secret +metadata: + name: $Name + namespace: $Namespace +type: Opaque +data: + client_id: $($app.AppId|ToBase64) + client_secret: $($secret.SecretText|ToBase64) + endpoint: $("https://login.microsoftonline.com/$((Get-AzContext).Tenant.Id)/v2.0"|ToBase64) + random_secret: $([guid]::NewGuid().Guid|ToBase64) +"@ + +Write-Verbose "$Path`n$Secret" + +Set-Content $Path $Secret -Encoding ascii + +sops -e -i $Path + +Pop-Location -StackName Initialize-AuthApplication + +# https://login.microsoftonline.com/$tenant/v2.0/.well-known/openid-configuration +# https://login.microsoftonline.com/$tenant/oauth2/v2.0/authorize \ No newline at end of file diff --git a/infrastructure/Install-Flux.ps1 b/Initialize-Flux.ps1 similarity index 96% rename from infrastructure/Install-Flux.ps1 rename to Initialize-Flux.ps1 index c6b04dd..3ec432e 100644 --- a/infrastructure/Install-Flux.ps1 +++ b/Initialize-Flux.ps1 @@ -1,6 +1,6 @@ <# .SYNOPSIS - Installs Flux v2 and bootstraps it to/from a git repository + Bootstraps Flux v2 to/from a git repository .DESCRIPTION The `flux bootstrap` command is idempotent, and besides installing (or upgrading) the controllers on the cluster, pushes the Flux manifests to the git repository, and configures Flux to update itself from Git. @@ -59,10 +59,10 @@ param( # The passphrase for the SSH key file [SecureString]$KeyPassphrase = $global:KeyPassphrase ) -Push-Location $PSScriptRoot/.. -StackName InstallFlux +Push-Location $PSScriptRoot -StackName InstallFlux # it's literally just a single file binary, but it comes in a zip/tar.gz so we'll just use the install script -$version = if (Get-Command flux) { +$version = if (Get-Command flux -ErrorAction Ignore) { (flux --version) -replace "flux version\s+" }