Skip to content

Commit f9892bb

Browse files
[Identity] Managed Identity test automation: Azure Functions and Webapps (Azure#28554)
1 parent 4c0a0fa commit f9892bb

24 files changed

+958
-3
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,3 +186,7 @@ sdk/template/template-dpg/src/src
186186

187187
# tshy
188188
.tshy-build-tmp
189+
190+
# sshkey
191+
sdk/**/sshkey
192+
sdk/**/sshkey.pub

eng/.docsettings.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ omitted_paths:
2323
- sdk/storage/storage-datalake/README.md
2424
- sdk/storage/storage-internal-avro/*
2525
- sdk/test-utils/*/README.md
26+
- sdk/identity/identity/integration/*
2627

2728
language: js
2829
root_check_enabled: True

sdk/identity/identity/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
src/**/*.js
2+
integration/AzureFunctions/app.zip
3+
integration/AzureWebApps/.azure/
24
!assets/fake-cert.pem
35
!assets/fake-cert-password.pem
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"bindings": [
3+
{
4+
"type": "httpTrigger",
5+
"direction": "in",
6+
"authLevel": "anonymous",
7+
"methods": ["get"],
8+
"name": "req"
9+
},
10+
{
11+
"type": "http",
12+
"direction": "out",
13+
"name": "res"
14+
}
15+
],
16+
"scriptFile": "./dist/authenticateToStorageFunction.js"
17+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"version": "2.0",
3+
"logging": {
4+
"applicationInsights": {
5+
"samplingSettings": {
6+
"isEnabled": true,
7+
"excludedTypes": "Request"
8+
}
9+
}
10+
},
11+
"extensionBundle": {
12+
"id": "Microsoft.Azure.Functions.ExtensionBundle",
13+
"version": "[4.0.0, 5.0.0)"
14+
}
15+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"IsEncrypted": false,
3+
"Values": {
4+
"FUNCTIONS_WORKER_RUNTIME": "node"
5+
},
6+
"ConnectionStrings": {}
7+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"name": "@azure-samples/azure-function-test",
3+
"version": "1.0.0",
4+
"description": "",
5+
"main": "dist/authenticateToStorageFunction.js",
6+
"scripts": {
7+
"build": "tsc",
8+
"build:production": "npm run prestart && npm prune --production",
9+
"clean": "rimraf --glob dist dist-*",
10+
"prestart": "npm run build:production && func extensions install",
11+
"start:host": "func start --typescript",
12+
"start": "npm-run-all --parallel start:host watch",
13+
"test": "echo \"Error: no test specified\" && exit 1"
14+
},
15+
"author": "",
16+
"license": "ISC",
17+
"dependencies": {
18+
"@azure/identity": "^4.0.0",
19+
"@azure/storage-blob": "^12.17.0",
20+
"@azure/functions": "^4.1.0",
21+
"applicationinsights": "^2.9.2",
22+
"tslib": "^1.10.0"
23+
},
24+
"devDependencies": {
25+
"npm-run-all": "^4.1.5",
26+
"typescript": "^5.3.3",
27+
"rimraf": "^5.0.5"
28+
}
29+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
2+
import { BlobServiceClient } from "@azure/storage-blob";
3+
import { ManagedIdentityCredential } from "@azure/identity";
4+
import { app, HttpRequest, HttpResponseInit, InvocationContext } from "@azure/functions";
5+
6+
export async function authenticateStorage(request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> {
7+
try {
8+
context.log('Http function was triggered.');
9+
//parse the request body
10+
await authToStorageHelper(context);
11+
12+
return {
13+
// status: 200, /* Defaults to 200 */
14+
body: "Successfully authenticated with storage",
15+
};
16+
} catch (error: any) {
17+
context.log(error);
18+
return {
19+
status: 400,
20+
body: error,
21+
};
22+
}
23+
};
24+
25+
app.http('authenticateStorage', {
26+
methods: ['GET', 'POST'],
27+
authLevel: "anonymous",
28+
handler: authenticateStorage
29+
});
30+
31+
async function authToStorageHelper(context: InvocationContext): Promise<void> {
32+
// This will use the system managed identity
33+
const credential1 = new ManagedIdentityCredential();
34+
35+
const clientId = process.env.IDENTITY_USER_DEFINED_IDENTITY_CLIENT_ID!;
36+
const account1 = process.env.IDENTITY_STORAGE_NAME_1;
37+
const account2 = process.env.IDENTITY_STORAGE_NAME_2;
38+
39+
const credential2 = new ManagedIdentityCredential({ "clientId": clientId });
40+
const client1 = new BlobServiceClient(`https://${account1}.blob.core.windows.net`, credential1);
41+
const client2 = new BlobServiceClient(`https://${account2}.blob.core.windows.net`, credential2);
42+
context.log("Getting containers for storage account client: system managed identity")
43+
let iter = client1.listContainers();
44+
let i = 1;
45+
context.log("Client with system assigned identity");
46+
let containerItem = await iter.next();
47+
while (!containerItem.done) {
48+
context.log(`Container ${i++}: ${containerItem.value.name}`);
49+
containerItem = await iter.next();
50+
}
51+
52+
context.log("Getting properties for storage account client: user assigned managed identity")
53+
iter = client2.listContainers();
54+
context.log("Client with user assigned identity");
55+
containerItem = await iter.next();
56+
while (!containerItem.done) {
57+
context.log(`Container ${i++}: ${containerItem.value.name}`);
58+
containerItem = await iter.next();
59+
}
60+
61+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"compilerOptions": {
3+
"target": "ES2020",
4+
"module": "commonjs",
5+
"moduleResolution": "node",
6+
"resolveJsonModule": true,
7+
"esModuleInterop": true,
8+
"strict": true,
9+
"alwaysStrict": true,
10+
"outDir": "dist",
11+
},
12+
"include": ["src"]
13+
}
14+
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# ------------------------------------
2+
# Copyright (c) Microsoft Corporation.
3+
# Licensed under the MIT License.
4+
# ------------------------------------
5+
ARG NODE_VERSION=20
6+
7+
# docker can't tell when the repo has changed and will therefore cache this layer
8+
# internal users should provide MCR registry to build via 'docker build . --build-arg REGISTRY="mcr.microsoft.com/mirror/docker/library/"'
9+
# public OSS users should simply leave this argument blank or ignore its presence entirely
10+
ARG REGISTRY=""
11+
12+
FROM ${REGISTRY}node:${NODE_VERSION}-alpine as repo
13+
RUN apk --no-cache add git
14+
RUN git clone https://github.com/azure/azure-sdk-for-js --single-branch --branch main --depth 1 /azure-sdk-for-js
15+
16+
WORKDIR /azure-sdk-for-js/sdk/identity/identity/test/integration/AzureKubernetes
17+
RUN npm install
18+
RUN npm install -g typescript
19+
RUN tsc -p .
20+
CMD ["node", "index"]

0 commit comments

Comments
 (0)