diff --git a/.pipelines/SecretManagement-Official.yml b/.pipelines/SecretManagement-Official.yml index 8759e60..c1eb774 100644 --- a/.pipelines/SecretManagement-Official.yml +++ b/.pipelines/SecretManagement-Official.yml @@ -26,11 +26,17 @@ parameters: default: false variables: - system.debug: ${{ parameters.debug }} - BuildConfiguration: Release - WindowsContainerImage: onebranch.azurecr.io/windows/ltsc2022/vse2022:latest - DOTNET_NOLOGO: true - DOTNET_GENERATE_ASPNET_CERTIFICATE: false +- name: system.debug + value: ${{ parameters.debug }} +- name: BuildConfiguration + value: Release +- name: WindowsContainerImage + value: onebranch.azurecr.io/windows/ltsc2022/vse2022:latest +- name: DOTNET_NOLOGO + value: true +- name: DOTNET_GENERATE_ASPNET_CERTIFICATE + value: false +- group: SecretManagementAcr resources: repositories: @@ -185,3 +191,109 @@ extends: packagesToPush: $(drop)/Microsoft.PowerShell.SecretManagement.Library.$(version).nupkg nuGetFeedType: external publishFeedCredentials: PowerShellNuGetOrgPush + - stage: PrepForEv2 + condition: ne(variables['Build.Reason'], 'Schedule') + dependsOn: build + variables: + drop: $(Pipeline.Workspace)/drop_build_main + version: $[ stageDependencies.build.main.outputs['package.version'] ] + jobs: + - job: CopyEv2FilesToArtifact + displayName: Copy Ev2 Files To Artifact + variables: + - name: ob_outputDirectory + value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' + pool: + timeoutInMinutes: 30 + type: windows + steps: + - task: onebranch.pipeline.signing@1 + displayName: Sign 1st Party Files + inputs: + command: 'sign' + signing_profile: external_distribution + files_to_sign: '**\*.ps1' + search_root: '$(Build.SourcesDirectory)/EV2Specs/ServiceGroupRoot/Shell' + - download: current + displayName: Download artifacts + - task: CopyFiles@2 + inputs: + SourceFolder: $(drop) + Contents: Microsoft.PowerShell.SecretManagement.$(version).nupkg + TargetFolder: $(Build.SourcesDirectory)/EV2Specs/ServiceGroupRoot/SrcFiles/ + - task: ArchiveFiles@2 + inputs: + rootFolderOrFile: $(Build.SourcesDirectory)/EV2Specs/ServiceGroupRoot/Shell/Run + includeRootFolder: false + archiveType: tar + tarCompression: none + archiveFile: $(Build.SourcesDirectory)/EV2Specs/ServiceGroupRoot/Shell/Run.tar + displayName: Compress Run script into tar file as needed for EV2 Shell extension + - pwsh: | + $pathToJsonFile = '$(Build.SourcesDirectory)/EV2Specs/ServiceGroupRoot/SecretManagementToACR.Rollout.json' + $content = Get-Content -Path $pathToJsonFile | ConvertFrom-Json + + $environmentVariables = @() + + $environmentVariables += [PSCustomObject]@{name="DESTINATION_ACR_NAME"; value='$(acr_name)'} + $environmentVariables += [PSCustomObject]@{name="DESTINATION_ACR_URI"; value='$(acr_uri)'} + $environmentVariables += [PSCustomObject]@{name="MI_NAME"; value='$(managed_identity_name)'} + $environmentVariables += [PSCustomObject]@{name="MI_CLIENTID"; value='$(managed_identity_clientid)'} + $environmentVariables += [PSCustomObject]@{name="SECRET_MANAGEMENT_VERSION"; value='$(version)'} + $environmentVariables += [PSCustomObject]@{name="SECRET_MANAGEMENT_MODULE"; reference=[PSCustomObject]@{path="SrcFiles\\Microsoft.PowerShell.SecretManagement.$(version).nupkg"}} + + $content.shellExtensions.launch.environmentVariables = $environmentVariables + + $identityString = "/subscriptions/$(acr_subscription)/resourcegroups/$(acr_resource_group)/providers/Microsoft.ManagedIdentity/userAssignedIdentities/$(managed_identity_name)" + $content.shellExtensions.launch.identity.userAssignedIdentities[0] = $identityString + + Remove-Item -Path $pathToJsonFile + $content | ConvertTo-Json -Depth 6 | Out-File $pathToJsonFile + displayName: 'Replace values in SecretManagementToACR.Rollout.json file' + - pwsh: | + $pathToJsonFile = Join-Path -Path '$(Build.SourcesDirectory)/EV2Specs/ServiceGroupRoot' -ChildPath 'RolloutSpec.json' + $content = Get-Content -Path $pathToJsonFile | ConvertFrom-Json + $content.RolloutMetadata.Notification.Email.To = '$(email_address)' + + Remove-Item -Path $pathToJsonFile + $content | ConvertTo-Json -Depth 4 | Out-File $pathToJsonFile + + displayName: 'Replace values in RolloutSpecPath.json' + - pwsh: | + $pathToJsonFile = Join-Path -Path '$(Build.SourcesDirectory)/EV2Specs/ServiceGroupRoot' -ChildPath 'ServiceModel.json' + $content = Get-Content -Path $pathToJsonFile | ConvertFrom-Json + $content.ServiceResourceGroups[0].AzureResourceGroupName = '$(acr_resource_group)' + $content.ServiceResourceGroups[0].AzureSubscriptionId = '$(acr_subscription)' + + Remove-Item -Path $pathToJsonFile + $content | ConvertTo-Json -Depth 9 | Out-File $pathToJsonFile + + displayName: 'Replace values in ServiceModel.json' + - task: CopyFiles@2 + inputs: + Contents: 'EV2Specs/**' + TargetFolder: $(ob_outputDirectory) + - stage: 'Prod_release' + displayName: Deploy Images to ACR with EV2 + dependsOn: + - PrepForEV2 + variables: + - name: ob_release_environment + value: "Production" + - name: repoRoot + value: $(Build.SourcesDirectory) + jobs: + - job: Prod_ReleaseJob + pool: + type: release + steps: + - download: current + displayName: Download artifacts + - task: vsrm-ev2.vss-services-ev2.adm-release-task.ExpressV2Internal@1 + displayName: 'Ev2: Push to ACR' + inputs: + UseServerMonitorTask: true + EndpointProviderType: ApprovalService + ApprovalServiceEnvironment: Production + ServiceRootPath: '$(Pipeline.Workspace)/drop_PrepForEV2_CopyEv2FilesToArtifact/EV2Specs/ServiceGroupRoot' + RolloutSpecPath: '$(Pipeline.Workspace)/drop_PrepForEV2_CopyEv2FilesToArtifact/EV2Specs/ServiceGroupRoot/RolloutSpec.json' diff --git a/Ev2Specs/ServiceGroupRoot/RolloutSpec.json b/Ev2Specs/ServiceGroupRoot/RolloutSpec.json new file mode 100644 index 0000000..1ca9f35 --- /dev/null +++ b/Ev2Specs/ServiceGroupRoot/RolloutSpec.json @@ -0,0 +1,28 @@ +{ + "$schema": "https://ev2schema.azure.net/schemas/2020-01-01/rolloutSpecification.json", + "contentVersion": "1.0.0.0", + "RolloutMetadata": { + "ServiceModelPath": "ServiceModel.json", + "ScopeBindingsPath": "ScopeBindings.json", + "Name": "OneBranch-Demo-Container-Deployment", + "RolloutType": "Major", + "BuildSource": { + "Parameters": { + "VersionFile": "buildver.txt" + } + }, + "Notification": { + "Email": { + "To": "default" + } + } + }, + "OrchestratedSteps": [ + { + "Name": "UploadSecretManagementToACR", + "TargetType": "ServiceResource", + "TargetName": "SecretManagementToACR", + "Actions": ["Shell/Run"] + } + ] + } diff --git a/Ev2Specs/ServiceGroupRoot/ScopeBindings.json b/Ev2Specs/ServiceGroupRoot/ScopeBindings.json new file mode 100644 index 0000000..d25d5a7 --- /dev/null +++ b/Ev2Specs/ServiceGroupRoot/ScopeBindings.json @@ -0,0 +1,23 @@ +{ + "$schema": "https://ev2schema.azure.net/schemas/2020-01-01/scopeBindings.json", + "contentVersion": "0.0.0.1", + "scopeBindings": [ + { + "scopeTagName": "Global", + "bindings": [ + { + "find": "__SUBSCRIPTION_ID__", + "replaceWith": "$azureSubscriptionId()" + }, + { + "find": "__RESOURCE_GROUP__", + "replaceWith": "$azureResourceGroup()" + }, + { + "find": "__BUILD_VERSION__", + "replaceWith": "$buildVersion()" + } + ] + } + ] + } diff --git a/Ev2Specs/ServiceGroupRoot/SecretManagementToACR.Rollout.json b/Ev2Specs/ServiceGroupRoot/SecretManagementToACR.Rollout.json new file mode 100644 index 0000000..9521934 --- /dev/null +++ b/Ev2Specs/ServiceGroupRoot/SecretManagementToACR.Rollout.json @@ -0,0 +1,60 @@ +{ + "$schema": "https://ev2schema.azure.net/schemas/2020-01-01/rolloutParameters.json", + "contentVersion": "1.0.0.0", + "shellExtensions": [ + { + "name": "Run", + "type": "Run", + "properties": { + "maxExecutionTime": "PT2H" + }, + "package": { + "reference": { + "path": "Shell/Run.tar" + } + }, + "launch": { + "command": [ + "/bin/bash", + "-c", + "pwsh ./Run/Run.ps1" + ], + "environmentVariables": [ + { + "name": "SECRET_MANAGEMENT_MODULE", + "reference": + { + "path": "SrcFiles\\Microsoft.PowerShell.SecretManagement.nupkg" + } + }, + { + "name": "DESTINATION_ACR_NAME", + "value": "default" + }, + { + "name": "MI_NAME", + "value": "default" + }, + { + "name": "MI_CLIENTID", + "value": "default" + }, + { + "name": "SECRET_MANAGEMENT_VERSION", + "value": "default" + }, + { + "name": "DESTINATION_ACR_URI", + "value": "default" + } + ], + "identity": { + "type": "userAssigned", + "userAssignedIdentities": [ + "default" + ] + } + } + } + ] + } diff --git a/Ev2Specs/ServiceGroupRoot/ServiceModel.json b/Ev2Specs/ServiceGroupRoot/ServiceModel.json new file mode 100644 index 0000000..871bbd4 --- /dev/null +++ b/Ev2Specs/ServiceGroupRoot/ServiceModel.json @@ -0,0 +1,51 @@ +{ + "$schema": "https://ev2schema.azure.net/schemas/2020-01-01/serviceModel.json", + "contentVersion": "1.0.0.0", + "ServiceMetadata": { + "ServiceGroup": "OneBranch-SecretManagement", + "Environment": "Test" + }, + "ServiceResourceGroupDefinitions": [ + { + "Name": "OneBranch-SecretManagement-RGDef", + "ServiceResourceDefinitions": [ + { + "Name": "OneBranch-SecretManagement.Shell-SRDef", + "composedOf": { + "extension": { + "shell": [ + { + "type": "Run", + "properties": { + "imageName": "adm-mariner-20-l", + "imageVersion": "v5" + } + } + ] + } + } + } + ] + } + ], + "ServiceResourceGroups": [ + { + "AzureResourceGroupName": "default", + "Location": "East US", + "InstanceOf": "OneBranch-SecretManagement-RGDef", + "AzureSubscriptionId": "default", + "scopeTags": [ + { + "name": "Global" + } + ], + "ServiceResources": [ + { + "Name": "SecretManagementToACR", + "InstanceOf": "OneBranch-SecretManagement.Shell-SRDef", + "RolloutParametersPath": "SecretManagementToACR.Rollout.json" + } + ] + } + ] + } diff --git a/Ev2Specs/ServiceGroupRoot/Shell/Run/Run.ps1 b/Ev2Specs/ServiceGroupRoot/Shell/Run/Run.ps1 new file mode 100644 index 0000000..749868b --- /dev/null +++ b/Ev2Specs/ServiceGroupRoot/Shell/Run/Run.ps1 @@ -0,0 +1,77 @@ +# ensure SAS variables were passed in +if ($env:SECRET_MANAGEMENT_MODULE -eq $null) +{ + Write-Verbose -Verbose "SECRET_MANAGEMENT_MODULE variable didn't get passed correctly" + return 1 +} + +if ($env:SECRET_MANAGEMENT_VERSION -eq $null) +{ + Write-Verbose -Verbose "SECRET_MANAGEMENT_VERSION variable didn't get passed correctly" + return 1 +} + +if ($env:DESTINATION_ACR_NAME -eq $null) +{ + Write-Verbose -Verbose "DESTINATION_ACR_NAME variable didn't get passed correctly" + return 1 +} + +if ($env:DESTINATION_ACR_URI -eq $null) +{ + Write-Verbose -Verbose "DESTINATION_ACR_URI variable didn't get passed correctly" + return 1 +} + +if ($env:MI_CLIENTID -eq $null) +{ + Write-Verbose -Verbose "MI_CLIENTID variable didn't get passed correctly" + return 1 +} + + +try { + Write-Verbose -Verbose "SecretManagement: $env:SECRET_MANAGEMENT_MODULE" + Write-Verbose -Verbose "Version: $env:SECRET_MANAGEMENT_VERSION" + Write-Verbose -Verbose "acrname: $env:DESTINATION_ACR_NAME" + Write-Verbose -Verbose "acruri: $env:DESTINATION_ACR_URI" + Write-Verbose -Verbose "MI client Id: $env:MI_CLIENTID" + + $secretManagementFileName = "Microsoft.PowerShell.SecretManagement.$($env:SECRET_MANAGEMENT_VERSION).nupkg" + + Write-Verbose -Verbose "Download files" + Invoke-WebRequest -Uri $env:SECRET_MANAGEMENT_MODULE -OutFile $secretManagementFileName + + $moduleExists = Test-Path $secretManagementFileName + Write-Verbose -Verbose "Module $secretManagementFileName exists: $moduleExists" + + # Install PSResourceGet 1.1.0 + Write-Verbose "Download PSResourceGet version 1.1.0" + Register-PSRepository -Name CFS -SourceLocation "https://pkgs.dev.azure.com/powershell/PowerShell/_packaging/powershell/nuget/v2" -InstallationPolicy Trusted + Install-Module -Repository CFS -Name Microsoft.PowerShell.PSResourceGet -RequiredVersion '1.1.0' -Verbose + Import-Module Microsoft.PowerShell.PSResourceGet + Get-Module + + # Login to Azure CLI using Managed Identity + Write-Verbose -Verbose "Login cli using managed identity" + az login --identity --username $env:MI_CLIENTID + + # Register the target ACR as a PSResourceGet repository + Write-Verbose -Verbose "Register ARC as a PSResourceGet reposirory" + Register-PSResourceRepository -Uri $env:DESTINATION_ACR_URI -Name $env:DESTINATION_ACR_NAME -Trusted -Verbose + + Get-PSResourceRepository + + #Publish SecretManagement to ACR + Write-Verbose -Verbose "Publish SecretManagement $secretManagementFileName to ACR $env:DESTINATION_ACR_NAME" + $prefix = "public/psresource" + Publish-PSResource -Repository $env:DESTINATION_ACR_NAME -NupkgPath $secretManagementFileName -ModulePrefix $prefix -Confirm:$false +} +catch { + + $_.Exception | Format-List -Force + + return 1 +} + +return 0 diff --git a/Ev2Specs/ServiceGroupRoot/buildver.txt b/Ev2Specs/ServiceGroupRoot/buildver.txt new file mode 100644 index 0000000..359a5b9 --- /dev/null +++ b/Ev2Specs/ServiceGroupRoot/buildver.txt @@ -0,0 +1 @@ +2.0.0 \ No newline at end of file