Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[keyvault] KeyVault Admin deployment fixes #31817

Merged
merged 6 commits into from
Dec 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion sdk/keyvault/keyvault-admin/assets.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
"AssetsRepo": "Azure/azure-sdk-assets",
"AssetsRepoPrefixPath": "js",
"TagPrefix": "js/keyvault/keyvault-admin",
"Tag": "js/keyvault/keyvault-admin_4b469d86ad"
"Tag": "js/keyvault/keyvault-admin_1ce65643a5"
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,14 @@ import { Recorder } from "@azure-tools/test-recorder";
import { KeyVaultBackupClient } from "../../src/index.js";
import { authenticate } from "./utils/authentication.js";
import { testPollerProperties } from "./utils/recorder.js";
import { getSasToken } from "./utils/common.js";
import { describe, it, beforeEach, afterEach, expect } from "vitest";
import { AbortError } from "@azure/abort-controller";
import { getEnvironmentVariable } from "./utils/common.js";

// TODO: https://github.com/Azure/azure-sdk-for-js/issues/30273
describe.skip("Aborting KeyVaultBackupClient's requests", () => {
describe("Aborting KeyVaultBackupClient's requests", () => {
let client: KeyVaultBackupClient;
let recorder: Recorder;
let blobStorageUri: string;
let blobSasToken: string;

let generateFakeUUID: () => string;

Expand All @@ -25,9 +23,10 @@ describe.skip("Aborting KeyVaultBackupClient's requests", () => {
recorder = authentication.recorder;
generateFakeUUID = authentication.generateFakeUUID;

const sasTokenData = getSasToken();
blobStorageUri = sasTokenData.blobStorageUri;
blobSasToken = sasTokenData.blobSasToken;
blobStorageUri = new URL(
getEnvironmentVariable("BLOB_CONTAINER_NAME"),
getEnvironmentVariable("BLOB_STORAGE_URI"),
).href;
});

afterEach(async function () {
Expand All @@ -39,7 +38,7 @@ describe.skip("Aborting KeyVaultBackupClient's requests", () => {
controller.abort();

await expect(
client.beginBackup(blobStorageUri, blobSasToken, {
client.beginBackup(blobStorageUri, {
...testPollerProperties,
abortSignal: controller.signal,
}),
Expand All @@ -52,7 +51,7 @@ describe.skip("Aborting KeyVaultBackupClient's requests", () => {
controller.abort();

await expect(
client.beginRestore(backupURI, blobSasToken, {
client.beginRestore(backupURI, {
...testPollerProperties,
abortSignal: controller.signal,
}),
Expand All @@ -66,7 +65,7 @@ describe.skip("Aborting KeyVaultBackupClient's requests", () => {
controller.abort();

await expect(
client.beginSelectiveKeyRestore("key-name", backupURI, blobSasToken, {
client.beginSelectiveKeyRestore("key-name", backupURI, {
...testPollerProperties,
abortSignal: controller.signal,
}),
Expand Down
61 changes: 20 additions & 41 deletions sdk/keyvault/keyvault-admin/test/public/backupClient.spec.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,33 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { isPlaybackMode, Recorder } from "@azure-tools/test-recorder";
import type { Recorder } from "@azure-tools/test-recorder";
import { isPlaybackMode } from "@azure-tools/test-recorder";

import { KeyVaultBackupClient } from "../../src/index.js";
import type { KeyVaultBackupClient } from "../../src/index.js";
import { authenticate } from "./utils/authentication.js";
import { testPollerProperties } from "./utils/recorder.js";
import { getSasToken } from "./utils/common.js";
import { delay } from "@azure/core-util";
import { KeyClient } from "@azure/keyvault-keys";
import type { KeyClient } from "@azure/keyvault-keys";
import { describe, it, expect, beforeEach, afterEach } from "vitest";
import { getEnvironmentVariable } from "./utils/common.js";

// TODO: https://github.com/Azure/azure-sdk-for-js/issues/30273
describe.skip("KeyVaultBackupClient", () => {
describe("KeyVaultBackupClient", () => {
let client: KeyVaultBackupClient;
let keyClient: KeyClient;

let recorder: Recorder;
let blobStorageUri: string;
let blobSasToken: string;

beforeEach(async function (ctx) {
const authentication = await authenticate(ctx);
client = authentication.backupClient;
keyClient = authentication.keyClient;
recorder = authentication.recorder;
const sasTokenData = getSasToken();
blobStorageUri = sasTokenData.blobStorageUri;
blobSasToken = sasTokenData.blobSasToken;
blobStorageUri = new URL(
getEnvironmentVariable("BLOB_CONTAINER_NAME"),
getEnvironmentVariable("BLOB_STORAGE_URI"),
).href;
});

afterEach(async function () {
Expand All @@ -36,15 +36,11 @@ describe.skip("KeyVaultBackupClient", () => {

describe("beginBackup", function () {
it("returns the correct backup result when successful", async function () {
const backupPoller = await client.beginBackup(
blobStorageUri,
blobSasToken,
testPollerProperties,
);
const backupPoller = await client.beginBackup(blobStorageUri, testPollerProperties);
await backupPoller.poll();

// A poller can be serialized and then resumed
const resumedPoller = await client.beginBackup(blobStorageUri, blobSasToken, {
const resumedPoller = await client.beginBackup(blobStorageUri, {
resumeFrom: backupPoller.toString(),
...testPollerProperties,
});
Expand All @@ -71,23 +67,18 @@ describe.skip("KeyVaultBackupClient", () => {

describe("beginRestore", function () {
it("full restore completes successfully", async function () {
const backupPoller = await client.beginBackup(
blobStorageUri,
blobSasToken,
testPollerProperties,
);
const backupPoller = await client.beginBackup(blobStorageUri, testPollerProperties);
const backupResult = await backupPoller.pollUntilDone();
expect(backupResult.folderUri).toBeDefined();

const restorePoller = await client.beginRestore(
backupResult.folderUri!,
blobSasToken,
testPollerProperties,
);
await restorePoller.poll();

// A poller can be serialized and then resumed
const resumedPoller = await client.beginRestore(backupResult.folderUri!, blobSasToken, {
const resumedPoller = await client.beginRestore(backupResult.folderUri!, {
...testPollerProperties,
resumeFrom: restorePoller.toString(),
});
Expand All @@ -110,16 +101,10 @@ describe.skip("KeyVaultBackupClient", () => {
}
});

// This test can only be run in playback mode because running a backup
// or restore puts the instance in a bad state (tracked in IcM).
it.skipIf(!isPlaybackMode())("selectiveKeyRestore completes successfully", async function () {
it("selectiveKeyRestore completes successfully", async function () {
const keyName = "rsa1";
await keyClient.createRsaKey(keyName);
const backupPoller = await client.beginBackup(
blobStorageUri,
blobSasToken,
testPollerProperties,
);
const backupPoller = await client.beginBackup(blobStorageUri, testPollerProperties);
const backupURI = await backupPoller.pollUntilDone();
expect(backupURI.folderUri).toBeDefined();

Expand All @@ -130,21 +115,15 @@ describe.skip("KeyVaultBackupClient", () => {
const selectiveKeyRestorePoller = await client.beginSelectiveKeyRestore(
keyName,
backupURI.folderUri!,
blobSasToken,
testPollerProperties,
);
await selectiveKeyRestorePoller.poll();

// A poller can be serialized and then resumed
const resumedPoller = await client.beginSelectiveKeyRestore(
keyName,
blobStorageUri,
blobSasToken,
{
...testPollerProperties,
resumeFrom: selectiveKeyRestorePoller.toString(),
},
);
const resumedPoller = await client.beginSelectiveKeyRestore(keyName, blobStorageUri, {
...testPollerProperties,
resumeFrom: selectiveKeyRestorePoller.toString(),
});
expect(resumedPoller.getOperationState().isStarted).toEqual(true); // without polling
expect(resumedPoller.getOperationState().jobId).toEqual(
selectiveKeyRestorePoller.getOperationState().jobId,
Expand Down
11 changes: 0 additions & 11 deletions sdk/keyvault/keyvault-admin/test/public/utils/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,3 @@ export function getEnvironmentVariable(envVarName: string): string {
}
return envVar;
}

/**
* Get a predefined SAS token and Storage URI to use when backing up a KeyVault
*/
export function getSasToken(): { blobStorageUri: string; blobSasToken: string } {
const baseStorageUri = getEnvironmentVariable("BLOB_STORAGE_URI").replace(/\/$/, "");
const blobStorageUri = `${baseStorageUri}/${getEnvironmentVariable("BLOB_CONTAINER_NAME")}`;
const blobSasToken = getEnvironmentVariable("BLOB_STORAGE_SAS_TOKEN");

return { blobStorageUri, blobSasToken };
}
4 changes: 4 additions & 0 deletions sdk/keyvault/test-resources-post.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -111,3 +111,7 @@ Log "Creating additional required role assignments for resource access."
New-AzKeyVaultRoleAssignment -HsmName $hsmName -RoleDefinitionName "Managed HSM Crypto Officer" -ObjectID $testApplicationOid
New-AzKeyVaultRoleAssignment -HsmName $hsmName -RoleDefinitionName "Managed HSM Crypto User" -ObjectID $testApplicationOid
Log "Role assignments created for '$testApplicationOid'"

Log "Associating managed identity with managed HSM"
Update-AzKeyVaultManagedHsm -HsmName $hsmName -ResourceGroupName $DeploymentOutputs["KEYVAULT_RESOURCE_GROUP"] -UserAssignedIdentity $DeploymentOutputs["MANAGED_IDENTITY_ID"]
Log "Managed identity associated with managed HSM - backup and restore using managed identity is enabled"
27 changes: 27 additions & 0 deletions sdk/keyvault/test-resources.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@ var networkAcls = {
ipRules: []
defaultAction: 'Allow'
}
var managedIdentityName = '${baseName}-managedIdentity'
var managedIdentityId = managedIdentity.id

resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = if (enableHsm) {
name: managedIdentityName
location: location
}

resource keyVault 'Microsoft.KeyVault/vaults@2024-04-01-preview' = {
name: kvName
Expand Down Expand Up @@ -66,6 +73,12 @@ resource managedHsm 'Microsoft.KeyVault/managedHSMs@2024-04-01-preview' = if (en
family: 'B'
name: 'Standard_B1'
}
identity: {
type: 'UserAssigned'
userAssignedIdentities: {
'${managedIdentityId}': {}
}
}
properties: {
publicNetworkAccess: 'Enabled'
networkAcls: networkAcls
Expand Down Expand Up @@ -113,6 +126,19 @@ resource blobContainer 'Microsoft.Storage/storageAccounts/blobServices/container
parent: blobService
}

resource managedIdentityRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid(resourceGroup().id, 'StorageBlobContributor', managedIdentityId)
properties: {
roleDefinitionId: subscriptionResourceId(
'Microsoft.Authorization/roleDefinitions',
'ba92f5b4-2d11-453d-a403-e96b0029c9fe'
)
principalId: managedIdentity.properties.principalId
scope: resourceGroup().id
principalType: 'ServicePrincipal'
}
}

resource appServicePlan 'Microsoft.Web/serverfarms@2023-12-01' = {
name: attestationFarm
location: location
Expand Down Expand Up @@ -151,3 +177,4 @@ output CLIENT_OBJECT_ID string = testApplicationOid
output BLOB_STORAGE_URI string = storageAccount.properties.primaryEndpoints.blob
output BLOB_CONTAINER_NAME string = blobContainerName
output AZURE_KEYVAULT_ATTESTATION_URI string = 'https://${webApp.properties.defaultHostName}/'
output MANAGED_IDENTITY_ID string = managedIdentityId
Loading
Loading