### Packages impacted by this PR

@azure/identity

### Issues associated with this PR

Contributes to #26434

### Describe the problem that is addressed by this PR

Adds AKS managed identity integration tests
This commit is contained in:
Maor Leger 2024-03-21 15:18:47 -07:00 коммит произвёл GitHub
Родитель aca940f3c1
Коммит 4e7bca982c
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
15 изменённых файлов: 276 добавлений и 250 удалений

4
.gitignore поставляемый
Просмотреть файл

@ -188,5 +188,5 @@ sdk/template/template-dpg/src/src
.tshy-build-tmp
# sshkey
sdk/**/sshkey
sdk/**/sshkey.pub
sdk/**/sshKey
sdk/**/sshKey.pub

1
sdk/identity/identity/.gitignore поставляемый
Просмотреть файл

@ -1,5 +1,6 @@
src/**/*.js
integration/AzureFunctions/app.zip
integration/AzureWebApps/.azure/
integration/kubeconfig.yaml
!assets/fake-cert.pem
!assets/fake-cert-password.pem

Просмотреть файл

@ -1,11 +1,13 @@
import { BlobServiceClient } from "@azure/storage-blob";
import { ManagedIdentityCredential } from "@azure/identity";
import { app, HttpRequest, HttpResponseInit, InvocationContext } from "@azure/functions";
export async function authenticateStorage(request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> {
export async function authenticateStorage(
request: HttpRequest,
context: InvocationContext,
): Promise<HttpResponseInit> {
try {
context.log('Http function was triggered.');
context.log("Http function was triggered.");
//parse the request body
await authToStorageHelper(context);
@ -20,26 +22,26 @@ export async function authenticateStorage(request: HttpRequest, context: Invocat
body: error,
};
}
};
}
app.http('authenticateStorage', {
methods: ['GET', 'POST'],
app.http("authenticateStorage", {
methods: ["GET", "POST"],
authLevel: "anonymous",
handler: authenticateStorage
handler: authenticateStorage,
});
async function authToStorageHelper(context: InvocationContext): Promise<void> {
// This will use the system managed identity
const credential1 = new ManagedIdentityCredential();
const clientId = process.env.IDENTITY_USER_DEFINED_IDENTITY_CLIENT_ID!;
const clientId = process.env.IDENTITY_USER_DEFINED_CLIENT_ID!;
const account1 = process.env.IDENTITY_STORAGE_NAME_1;
const account2 = process.env.IDENTITY_STORAGE_NAME_2;
const credential2 = new ManagedIdentityCredential({ "clientId": clientId });
const credential2 = new ManagedIdentityCredential({ clientId });
const client1 = new BlobServiceClient(`https://${account1}.blob.core.windows.net`, credential1);
const client2 = new BlobServiceClient(`https://${account2}.blob.core.windows.net`, credential2);
context.log("Getting containers for storage account client: system managed identity")
context.log("Getting containers for storage account client: system managed identity");
let iter = client1.listContainers();
let i = 1;
context.log("Client with system assigned identity");
@ -49,7 +51,7 @@ async function authToStorageHelper(context: InvocationContext): Promise<void> {
containerItem = await iter.next();
}
context.log("Getting properties for storage account client: user assigned managed identity")
context.log("Getting properties for storage account client: user assigned managed identity");
iter = client2.listContainers();
context.log("Client with user assigned identity");
containerItem = await iter.next();
@ -57,5 +59,4 @@ async function authToStorageHelper(context: InvocationContext): Promise<void> {
context.log(`Container ${i++}: ${containerItem.value.name}`);
containerItem = await iter.next();
}
}

Просмотреть файл

@ -10,11 +10,12 @@ ARG NODE_VERSION=20
ARG REGISTRY=""
FROM ${REGISTRY}node:${NODE_VERSION}-alpine as repo
RUN apk --no-cache add git
RUN git clone https://github.com/azure/azure-sdk-for-js --single-branch --branch main --depth 1 /azure-sdk-for-js
WORKDIR /app
WORKDIR /azure-sdk-for-js/sdk/identity/identity/test/integration/AzureKubernetes
RUN npm install
RUN npm install -g typescript
RUN tsc -p .
CMD ["node", "index"]
COPY . .
# Install the latest nightly build of identity
RUN npm install --no-package-lock
# Wait for the test to `exec` into the container and run the script
CMD ["sleep", "infinity"]

Просмотреть файл

@ -0,0 +1,51 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
const { BlobServiceClient } = require("@azure/storage-blob");
const { ManagedIdentityCredential, WorkloadIdentityCredential } = require("@azure/identity");
async function main() {
const storageAccount = process.env.IDENTITY_STORAGE_NAME_2;
if (!storageAccount) {
throw new Error("Missing IDENTITY_STORAGE_NAME_2 env var");
}
const clientId = process.env.IDENTITY_USER_DEFINED_CLIENT_ID;
if (!clientId) {
throw new Error("Missing IDENTITY_USER_DEFINED_CLIENT_ID env var");
}
const blobUrl = `https://${storageAccount}.blob.core.windows.net`;
try {
const blobServiceClient = new BlobServiceClient(
blobUrl,
new ManagedIdentityCredential({
clientId,
}),
);
await blobServiceClient.getProperties();
// The test looks for this line in the output
console.log("ManagedIdentity: Successfully authenticated with storage");
} catch (e) {
console.error(e);
}
try {
const blobServiceClient = new BlobServiceClient(
blobUrl,
new WorkloadIdentityCredential({
clientId,
}),
);
await blobServiceClient.getProperties();
// The test looks for this line in the output
console.log("WorkloadIdentity: Successfully authenticated with storage");
} catch (e) {
console.error(e);
}
}
main().then(console.log).catch(console.error);

Просмотреть файл

@ -1,22 +1,13 @@
{
"name": "@azure-samples/azure-kubernetes-test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "tsc",
"start": "ts-node src/index.ts",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"@azure/identity": "^4.0.0",
"@azure/storage-blob": "^12.17.0",
"tslib": "^1.10.0",
"ts-node": "10.9.2"
},
"devDependencies": {
"typescript": "^5.3.3"
}
"name": "@azure-samples/azure-kubernetes-test",
"version": "1.0.0",
"description": "A simple node JS script that can be used to test MSI on Kubernetes",
"main": "index.js",
"scripts": {},
"author": "",
"license": "ISC",
"dependencies": {
"@azure/identity": "dev",
"@azure/storage-blob": "^12.17.0"
}
}

Просмотреть файл

@ -1,48 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import { ManagedIdentityCredential } from "@azure/identity";
import { BlobServiceClient } from "@azure/storage-blob";
import * as dotenv from "dotenv";
// Initialize the environment
dotenv.config();
async function main(): Promise<void> {
let systemSuccessMessage = "";
try{
const account1 = process.env.IDENTITY_STORAGE_NAME_1;
const account2 = process.env.IDENTITY_STORAGE_NAME_2;
const credentialSystemAssigned = new ManagedIdentityCredential();
const credentialUserAssigned = new ManagedIdentityCredential({clientId: process.env.IDENTITY_USER_DEFINED_IDENTITY_CLIENT_ID})
const client1 = new BlobServiceClient(`https://${account1}.blob.core.windows.net`, credentialSystemAssigned);
const client2 = new BlobServiceClient(`https://${account2}.blob.core.windows.net`, credentialUserAssigned);
let iter = client1.listContainers();
let i = 1;
console.log("Client with system assigned identity");
let containerItem = await iter.next();
while (!containerItem.done) {
console.log(`Container ${i++}: ${containerItem.value.name}`);
containerItem = await iter.next();
}
systemSuccessMessage = "Successfully acquired token with system-assigned ManagedIdentityCredential"
console.log("Client with user assigned identity")
iter = client2.listContainers();
i = 1;
containerItem = await iter.next();
while (!containerItem.done) {
console.log(`Container ${i++}: ${containerItem.value.name}`);
containerItem = await iter.next();
}
console.log("Successfully acquired tokens with async ManagedIdentityCredential")
}
catch(e){
console.error(`${e} \n ${systemSuccessMessage}`);
}
}
main().catch((err) => {
console.log("error code: ", err.code);
console.log("error message: ", err.message);
console.log("error stack: ", err.stack);
});

Просмотреть файл

@ -1,13 +0,0 @@
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"moduleResolution": "node",
"resolveJsonModule": true,
"esModuleInterop": true,
"strict": true,
"alwaysStrict": true,
"outDir": "dist",
"rootDir": "."
}
}

Просмотреть файл

@ -12,7 +12,7 @@
"author": "",
"license": "ISC",
"dependencies": {
"@azure/identity": "^4.0.0",
"@azure/identity": "dev",
"@azure/storage-blob": "^12.17.0",
"express": "^4.18.2",
"tslib": "^1.10.0"

Просмотреть файл

@ -10,15 +10,18 @@ dotenv.config();
const app = express();
app.get("/", (req: express.Request, res: express.Response) => {
res.send("Ok")
})
res.send("Ok");
});
app.get("/sync", async (req: express.Request, res: express.Response) => {
let systemSuccessMessage = "";
try {
const account1 = process.env.IDENTITY_STORAGE_NAME_1;
const credentialSystemAssigned = new ManagedIdentityCredential();
const client1 = new BlobServiceClient(`https://${account1}.blob.core.windows.net`, credentialSystemAssigned);
const client1 = new BlobServiceClient(
`https://${account1}.blob.core.windows.net`,
credentialSystemAssigned,
);
let iter = client1.listContainers();
let i = 0;
console.log("Client with system assigned identity");
@ -29,31 +32,35 @@ app.get("/sync", async (req: express.Request, res: express.Response) => {
}
console.log("Client with system assigned identity");
console.log("Properties of the 1st client =", iter);
systemSuccessMessage = "Successfully acquired token with system-assigned ManagedIdentityCredential"
systemSuccessMessage =
"Successfully acquired token with system-assigned ManagedIdentityCredential";
console.log(systemSuccessMessage);
}
catch (e) {
} catch (e) {
console.error(e);
}
try {
const account2 = process.env.IDENTITY_STORAGE_NAME_2;
const credentialUserAssigned = new ManagedIdentityCredential({ clientId: process.env.IDENTITY_USER_DEFINED_IDENTITY_CLIENT_ID })
const client2 = new BlobServiceClient(`https://${account2}.blob.core.windows.net`, credentialUserAssigned);
const credentialUserAssigned = new ManagedIdentityCredential({
clientId: process.env.IDENTITY_USER_DEFINED_CLIENT_ID,
});
const client2 = new BlobServiceClient(
`https://${account2}.blob.core.windows.net`,
credentialUserAssigned,
);
let iter = client2.listContainers();
let i = 0;
console.log("Client with user assigned identity")
console.log("Client with user assigned identity");
let containerItem = await iter.next();
while (!containerItem.done) {
console.log(`Container ${i++}: ${containerItem.value.name}`);
containerItem = await iter.next();
}
res.status(200).send("Successfully acquired tokens with async ManagedIdentityCredential")
}
catch (e) {
res.status(200).send("Successfully acquired tokens with async ManagedIdentityCredential");
} catch (e) {
console.error(e);
res.status(500).send(`${e} \n ${systemSuccessMessage}`);
}
})
});
app.listen(8080, () => {
console.log(`Authorization code redirect server listening on port 8080`);

Просмотреть файл

@ -55,7 +55,7 @@
"format": "dev-tool run vendored prettier --write --config ../../../.prettierrc.json --ignore-path ../../../.prettierignore \"src/**/*.ts\" \"test/**/*.ts\" \"samples-dev/**/*.ts\" \"*.{js,json}\"",
"check-format": "dev-tool run vendored prettier --list-different --config ../../../.prettierrc.json --ignore-path ../../../.prettierignore \"src/**/*.ts\" \"test/**/*.ts\" \"samples-dev/**/*.ts\" \"*.{js,json}\"",
"integration-test:browser": "echo skipped",
"integration-test:node": "dev-tool run test:node-ts-input -- --timeout 180000 'test/public/node/*.spec.ts' 'test/internal/node/*.spec.ts' 'test/integration/*.spec.ts'",
"integration-test:node": "dev-tool run test:node-ts-input -- --timeout 180000 'test/public/node/*.spec.ts' 'test/internal/node/*.spec.ts' 'test/integration/**/*.spec.ts'",
"integration-test": "npm run integration-test:node && npm run integration-test:browser",
"lint:fix": "eslint package.json api-extractor.json src test --ext .ts --fix --fix-type [problem,suggestion]",
"lint": "eslint package.json api-extractor.json src test --ext .ts",

Просмотреть файл

@ -0,0 +1,76 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import { assert } from "chai";
import { execSync } from "child_process";
import { isLiveMode } from "@azure-tools/test-recorder";
describe("Azure Kubernetes Integration test", function () {
let podOutput: string;
before(async function () {
if (!isLiveMode()) {
this.skip();
}
const resourceGroup = requireEnvVar("IDENTITY_RESOURCE_GROUP");
const aksClusterName = requireEnvVar("IDENTITY_AKS_CLUSTER_NAME");
const subscriptionId = requireEnvVar("IDENTITY_SUBSCRIPTION_ID");
const podName = requireEnvVar("IDENTITY_AKS_POD_NAME");
if (process.env.IDENTITY_CLIENT_SECRET) {
// Log in as service principal in CI
const clientId = requireEnvVar("IDENTITY_CLIENT_ID");
const clientSecret = requireEnvVar("IDENTITY_CLIENT_SECRET");
const tenantId = requireEnvVar("IDENTITY_TENANT_ID");
runCommand(
"az",
`login --service-principal -u ${clientId} -p ${clientSecret} --tenant ${tenantId}`,
);
}
runCommand("az", `account set --subscription ${subscriptionId}`);
runCommand(
"az",
`aks get-credentials --resource-group ${resourceGroup} --name ${aksClusterName}`,
);
const pods = runCommand("kubectl", `get pods -o jsonpath='{.items[0].metadata.name}'`);
assert.include(pods, podName);
podOutput = runCommand("kubectl", `exec ${podName} -- node /app/index.js`);
});
it("can authenticate using managed identity", async function () {
if (!isLiveMode()) {
this.skip();
}
assert.include(
podOutput,
"ManagedIdentity: Successfully authenticated with storage",
`Expected ${podOutput} to include a ManagedIdentity success message`,
);
});
it("can authenticate using workload identity", async function () {
if (!isLiveMode()) {
this.skip();
}
assert.include(
podOutput,
"WorkloadIdentity: Successfully authenticated with storage",
`Expected ${podOutput} to include a WorkloadIdentity success message`,
);
});
});
function runCommand(command: string, args: string = ""): string {
return execSync(`${command} ${args}`).toString().trim();
}
function requireEnvVar(name: string): string {
const value = process.env[name];
if (!value) {
throw new Error(`Required env var ${name} is not set`);
}
return value;
}

Просмотреть файл

@ -8,14 +8,18 @@ param (
$RemainingArguments,
[Parameter()]
[hashtable] $DeploymentOutputs
[hashtable] $DeploymentOutputs,
[Parameter()]
[switch] $CI = ($null -ne $env:SYSTEM_TEAMPROJECTID)
)
# If not Linux, skip this script.
# if ($isLinux -ne "Linux") {
# Write-Host "Skipping post-deployment because not running on Linux."
# return
# }
$MIClientId = $DeploymentOutputs['IDENTITY_USER_DEFINED_CLIENT_ID']
$MIName = $DeploymentOutputs['IDENTITY_USER_DEFINED_IDENTITY_NAME']
$saAccountName = 'workload-identity-sa'
$podName = $DeploymentOutputs['IDENTITY_AKS_POD_NAME']
$storageName2 = $DeploymentOutputs['IDENTITY_STORAGE_NAME_2']
$userDefinedClientId = $DeploymentOutputs['IDENTITY_USER_DEFINED_CLIENT_ID']
$ErrorActionPreference = 'Continue'
$PSNativeCommandUseErrorActionPreference = $true
@ -25,8 +29,11 @@ $workingFolder = $webappRoot;
Write-Host "Working directory: $workingFolder"
az login --service-principal -u $DeploymentOutputs['IDENTITY_CLIENT_ID'] -p $DeploymentOutputs['IDENTITY_CLIENT_SECRET'] --tenant $DeploymentOutputs['IDENTITY_TENANT_ID']
az account set --subscription $DeploymentOutputs['IDENTITY_SUBSCRIPTION_ID']
if ($CI) {
Write-Host "Logging in to service principal"
az login --service-principal -u $DeploymentOutputs['IDENTITY_CLIENT_ID'] -p $DeploymentOutputs['IDENTITY_CLIENT_SECRET'] --tenant $DeploymentOutputs['IDENTITY_TENANT_ID']
az account set --subscription $DeploymentOutputs['IDENTITY_SUBSCRIPTION_ID']
}
# Azure Functions app deployment
Write-Host "Building the code for functions app"
@ -38,102 +45,76 @@ Write-Host "starting azure functions deployment"
Compress-Archive -Path "$workingFolder/AzureFunctions/RunTest/*" -DestinationPath "$workingFolder/AzureFunctions/app.zip" -Force
az functionapp deployment source config-zip -g $DeploymentOutputs['IDENTITY_RESOURCE_GROUP'] -n $DeploymentOutputs['IDENTITY_FUNCTION_NAME'] --src "$workingFolder/AzureFunctions/app.zip"
Remove-Item -Force "$workingFolder/AzureFunctions/app.zip"
Write-Host "Deployed function app"
# $image = "$loginServer/identity-functions-test-image"
# docker build --no-cache -t $image "$workingFolder/AzureFunctions"
# docker push $image
# az functionapp config container set -g $DeploymentOutputs['IDENTITY_RESOURCE_GROUP'] -n $DeploymentOutputs['IDENTITY_FUNCTION_NAME'] -i $image -r $loginServer -p $(az acr credential show -n $DeploymentOutputs['IDENTITY_ACR_NAME'] --query "passwords[0].value" -o tsv) -u $(az acr credential show -n $DeploymentOutputs['IDENTITY_ACR_NAME'] --query username -o tsv)
# Azure Web Apps app deployment
# Push-Location "$webappRoot/AzureWebApps"
# npm install
# npm run build
# Compress-Archive -Path "$workingFolder/AzureWebApps/*" -DestinationPath "$workingFolder/AzureWebApps/app.zip" -Force
# az webapp deploy --resource-group $DeploymentOutputs['IDENTITY_RESOURCE_GROUP'] --name $DeploymentOutputs['IDENTITY_WEBAPP_NAME'] --src-path "$workingFolder/AzureWebApps/app.zip" --async true
# Remove-Item -Force "$workingFolder/AzureWebApps/app.zip"
# Pop-Location
Write-Host "Deplying Identity Web App"
Push-Location "$webappRoot/AzureWebApps"
npm install
npm run build
az webapp up --resource-group $DeploymentOutputs['IDENTITY_RESOURCE_GROUP'] --name $DeploymentOutputs['IDENTITY_WEBAPP_NAME'] --plan $DeploymentOutputs['IDENTITY_WEBAPP_PLAN'] --runtime NODE:18-lts
Pop-Location
Write-Host "Deployed Identity Web App"
Write-Host "Deployed webapp"
Write-Host "Sleeping for a bit to ensure logs is ready."
Start-Sleep -Seconds 300
Write-Host "Deploying Identity Docker image to ACR"
az acr login -n $DeploymentOutputs['IDENTITY_ACR_NAME']
$loginServer = az acr show -n $DeploymentOutputs['IDENTITY_ACR_NAME'] --query loginServer -o tsv
$image = "$loginServer/identity-aks-test-image"
docker build --no-cache -t $image "$workingFolder/AzureKubernetes"
docker push $image
Write-Host "Deployed image to ACR"
# Write-Host "Sleeping for a bit to ensure container registry is ready."
# Start-Sleep -Seconds 20
# Write-Host "trying to login to acr"
# az acr login -n $DeploymentOutputs['IDENTITY_ACR_NAME']
# $loginServer = az acr show -n $DeploymentOutputs['IDENTITY_ACR_NAME'] --query loginServer -o tsv
Write-Host "Configuring kubernetes to use our image"
az aks update -n $DeploymentOutputs['IDENTITY_AKS_CLUSTER_NAME'] -g $DeploymentOutputs['IDENTITY_RESOURCE_GROUP'] --attach-acr $DeploymentOutputs['IDENTITY_ACR_NAME']
# # Azure Kubernetes Service deployment
# $image = "$loginServer/identity-aks-test-image"
# docker build --no-cache -t $image "$workingFolder/AzureKubernetes"
# docker push $image
# Get the aks cluster credentials
Write-Host "Getting AKS credentials"
az aks get-credentials --resource-group $DeploymentOutputs['IDENTITY_RESOURCE_GROUP'] --name $DeploymentOutputs['IDENTITY_AKS_CLUSTER_NAME']
# Attach the ACR to the AKS cluster
# Write-Host "Attaching ACR to AKS cluster"
# az aks update -n $DeploymentOutputs['IDENTITY_AKS_CLUSTER_NAME'] -g $DeploymentOutputs['IDENTITY_RESOURCE_GROUP'] --attach-acr $DeploymentOutputs['IDENTITY_ACR_NAME']
#Get the aks cluster OIDC issuer
Write-Host "Getting AKS OIDC issuer"
$AKS_OIDC_ISSUER = az aks show -n $DeploymentOutputs['IDENTITY_AKS_CLUSTER_NAME'] -g $DeploymentOutputs['IDENTITY_RESOURCE_GROUP'] --query "oidcIssuerProfile.issuerUrl" -otsv
# $MIClientId = $DeploymentOutputs['IDENTITY_USER_DEFINED_IDENTITY_CLIENT_ID']
# $MIName = $DeploymentOutputs['IDENTITY_USER_DEFINED_IDENTITY_NAME']
# $SaAccountName = 'workload-identity-sa'
# $PodName = $DeploymentOutputs['IDENTITY_AKS_POD_NAME']
# $storageName = $DeploymentOutputs['IDENTITY_STORAGE_NAME_2']
# # Get the aks cluster credentials
# Write-Host "Getting AKS credentials"
# az aks get-credentials --resource-group $DeploymentOutputs['IDENTITY_RESOURCE_GROUP'] --name $DeploymentOutputs['IDENTITY_AKS_CLUSTER_NAME']
# Create the federated identity
Write-Host "Creating federated identity"
az identity federated-credential create --name $MIName --identity-name $MIName --resource-group $DeploymentOutputs['IDENTITY_RESOURCE_GROUP'] --issuer $AKS_OIDC_ISSUER --subject system:serviceaccount:default:workload-identity-sa
# #Get the aks cluster OIDC issuer
# Write-Host "Getting AKS OIDC issuer"
# $AKS_OIDC_ISSUER = az aks show -n $DeploymentOutputs['IDENTITY_AKS_CLUSTER_NAME'] -g $DeploymentOutputs['IDENTITY_RESOURCE_GROUP'] --query "oidcIssuerProfile.issuerUrl" -otsv
# Build the kubernetes deployment yaml
$kubeConfig = @"
apiVersion: v1
kind: ServiceAccount
metadata:
annotations:
azure.workload.identity/client-id: $MIClientId
name: $saAccountName
namespace: default
---
apiVersion: v1
kind: Pod
metadata:
name: $podName
namespace: default
labels:
azure.workload.identity/use: "true"
spec:
serviceAccountName: $saAccountName
containers:
- name: $podName
image: $image
env:
- name: IDENTITY_STORAGE_NAME_2
value: "$storageName2"
- name: IDENTITY_USER_DEFINED_CLIENT_ID
value: "$userDefinedClientId"
ports:
- containerPort: 80
nodeSelector:
kubernetes.io/os: linux
"@
# # Create the federated identity
# Write-Host "Creating federated identity"
# az identity federated-credential create --name $MIName --identity-name $MIName --resource-group $DeploymentOutputs['IDENTITY_RESOURCE_GROUP'] --issuer $AKS_OIDC_ISSUER --subject system:serviceaccount:default:workload-identity-sa
Write-Host $kubeConfig
Set-Content -Path "$workingFolder/kubeconfig.yaml" -Value $kubeConfig
# # Build the kubernetes deployment yaml
# $kubeConfig = @"
# apiVersion: v1
# kind: ServiceAccount
# metadata:
# annotations:
# azure.workload.identity/client-id: $MIClientId
# name: $SaAccountName
# namespace: default
# ---
# apiVersion: v1
# kind: Pod
# metadata:
# name: $PodName
# namespace: default
# labels:
# azure.workload.identity/use: "true"
# spec:
# serviceAccountName: $SaAccountName
# containers:
# - name: $PodName
# image: $image
# env:
# - name: IDENTITY_STORAGE_NAME
# value: "$StorageName"
# ports:
# - containerPort: 80
# nodeSelector:
# kubernetes.io/os: linux
# "@
# Set-Content -Path "$workingFolder/kubeconfig.yaml" -Value $kubeConfig
# Write-Host "Created kubeconfig.yaml with contents:"
# Write-Host $kubeConfig
# # Apply the config
# kubectl apply -f "$workingFolder/kubeconfig.yaml" --overwrite=true
# Write-Host "Applied kubeconfig.yaml"
# az logout
# Apply the config
kubectl apply -f "$workingFolder/kubeconfig.yaml" --overwrite=true
Write-Host "Applied kubeconfig.yaml"

Просмотреть файл

@ -8,24 +8,6 @@ param (
[Parameter(ValueFromRemainingArguments = $true)]
$RemainingArguments,
[Parameter()]
[string] $Location = '',
[Parameter()]
[ValidatePattern('^[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}$')]
[string] $TestApplicationId,
[Parameter()]
[string] $TestApplicationSecret,
[Parameter()]
[ValidatePattern('^[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}$')]
[string] $SubscriptionId,
[Parameter(ParameterSetName = 'Provisioner', Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[string] $TenantId,
[Parameter()]
[switch] $CI = ($null -ne $env:SYSTEM_TEAMPROJECTID)
@ -33,27 +15,20 @@ param (
Import-Module -Name $PSScriptRoot/../../eng/common/scripts/X509Certificate2 -Verbose
Remove-Item $PSScriptRoot/sshKey* -Force
ssh-keygen -t rsa -b 4096 -f $PSScriptRoot/sshKey -N '' -C ''
$sshKey = Get-Content $PSScriptRoot/sshKey.pub
$templateFileParameters['sshPubKey'] = $sshKey
Write-Host "Sleeping for a bit to ensure service principal is ready."
Start-Sleep -s 45
if ($CI) {
# Install this specific version of the Azure CLI to avoid https://github.com/Azure/azure-cli/issues/28358.
pip install azure-cli=="2.56.0"
# The owner is a service principal
$templateFileParameters['principalUserType'] = 'ServicePrincipal'
Write-Host "Sleeping for a bit to ensure service principal is ready."
Start-Sleep -s 45
}
$az_version = az version
Write-Host "Azure CLI version: $az_version"
az login --service-principal -u $TestApplicationId -p $TestApplicationSecret --tenant $TenantId
az account set --subscription $SubscriptionId
$versions = az aks get-versions -l westus -o json | ConvertFrom-Json
Write-Host "AKS versions: $($versions | ConvertTo-Json -Depth 100)"
$patchVersions = $versions.values | Where-Object { $_.isPreview -eq $null } | Select-Object -ExpandProperty patchVersions
Write-Host "AKS patch versions: $($patchVersions | ConvertTo-Json -Depth 100)"
$latestAksVersion = $patchVersions | Get-Member -MemberType NoteProperty | Select-Object -ExpandProperty Name | Sort-Object -Descending | Select-Object -First 1
Write-Host "Latest AKS version: $latestAksVersion"
$templateFileParameters['latestAksVersion'] = $latestAksVersion

Просмотреть файл

@ -15,7 +15,7 @@ param testApplicationOid string
param acrName string = 'acr${uniqueString(resourceGroup().id)}'
@description('The latest AKS version available in the region.')
param latestAksVersion string
param latestAksVersion string = '1.27.7'
@description('The SSH public key to use for the Linux VMs.')
param sshPubKey string
@ -23,9 +23,12 @@ param sshPubKey string
@description('The admin user name for the Linux VMs.')
param adminUserName string = 'azureuser'
@description('The user type - ServicePrincipal in CI, User locally')
param principalUserType string = 'User'
// https://learn.microsoft.com/azure/role-based-access-control/built-in-roles
// var blobContributor = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe') // Storage Blob Data Contributor
var blobOwner = subscriptionResourceId('Microsoft.Authorization/roleDefinitions','b7e6dc6d-f1e8-4753-8033-0f276bb0955b') // Storage Blob Data Owner
var serviceOwner = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')
var websiteContributor = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'de139f84-1756-47ae-9be6-808fbbe84772') // Website Contributor
// Cluster parameters
@ -61,7 +64,7 @@ resource blobRoleCluster 'Microsoft.Authorization/roleAssignments@2022-04-01' =
name: guid(resourceGroup().id, blobOwner, 'kubernetes')
properties: {
principalId: kubernetesCluster.identity.principalId
roleDefinitionId: blobOwner
roleDefinitionId: serviceOwner
principalType: 'ServicePrincipal'
}
}
@ -71,7 +74,7 @@ resource blobRole2 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid(resourceGroup().id, blobOwner, userAssignedIdentity.id)
properties: {
principalId: userAssignedIdentity.properties.principalId
roleDefinitionId: blobOwner
roleDefinitionId: serviceOwner
principalType: 'ServicePrincipal'
}
}
@ -82,7 +85,7 @@ resource webRole 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
properties: {
principalId: testApplicationOid
roleDefinitionId: websiteContributor
principalType: 'ServicePrincipal'
principalType: principalUserType
}
}
@ -92,12 +95,12 @@ resource webRole2 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
properties: {
principalId: testApplicationOid
roleDefinitionId: websiteContributor
principalType: 'ServicePrincipal'
principalType: principalUserType
}
}
resource storageAccount 'Microsoft.Storage/storageAccounts@2021-08-01' = {
name: baseName
name: uniqueString(resourceGroup().id)
location: location
sku: {
name: 'Standard_LRS'
@ -109,7 +112,7 @@ resource storageAccount 'Microsoft.Storage/storageAccounts@2021-08-01' = {
}
resource storageAccount2 'Microsoft.Storage/storageAccounts@2021-08-01' = {
name: '${baseName}2'
name: '${uniqueString(resourceGroup().id)}2'
location: location
sku: {
name: 'Standard_LRS'
@ -169,7 +172,7 @@ resource web 'Microsoft.Web/sites@2022-09-01' = {
value: storageAccount2.name
}
{
name: 'IDENTITY_USER_DEFINED_IDENTITY_CLIENT_ID'
name: 'IDENTITY_USER_DEFINED_CLIENT_ID'
value: userAssignedIdentity.properties.clientId
}
{
@ -210,7 +213,7 @@ resource azureFunction 'Microsoft.Web/sites@2022-09-01' = {
value: storageAccount2.name
}
{
name: 'IDENTITY_USER_DEFINED_IDENTITY_CLIENT_ID'
name: 'IDENTITY_USER_DEFINED_CLIENT_ID'
value: userAssignedIdentity.properties.clientId
}
{
@ -321,7 +324,7 @@ resource kubernetesCluster 'Microsoft.ContainerService/managedClusters@2023-06-0
output IDENTITY_WEBAPP_NAME string = web.name
output IDENTITY_WEBAPP_PLAN string = farm.name
output IDENTITY_USER_DEFINED_IDENTITY string = userAssignedIdentity.id
output IDENTITY_USER_DEFINED_IDENTITY_CLIENT_ID string = userAssignedIdentity.properties.clientId
output IDENTITY_USER_DEFINED_CLIENT_ID string = userAssignedIdentity.properties.clientId
output IDENTITY_USER_DEFINED_IDENTITY_NAME string = userAssignedIdentity.name
output IDENTITY_STORAGE_NAME_1 string = storageAccount.name
output IDENTITY_STORAGE_NAME_2 string = storageAccount2.name