Skip to content

Commit

Permalink
Add ExpressRoutePort MACsec SCI state (#13928)
Browse files Browse the repository at this point in the history
* Migrate macsec changes from broken repo

* Move get service principal id into PS script.  Add documentation in PS test cript

* Update ChangeLog.md

* Add SciState to Get-AzExpressRoutePort help examples

* Add test record
  • Loading branch information
francescanarea authored Jan 31, 2021
1 parent 5d9d398 commit 23694e8
Show file tree
Hide file tree
Showing 8 changed files with 2,861 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"vaultName": {
"value": "ps109"
},
"location": {
"value": "East US"
},
"tenantId": {
"value": "72f988bf-86f1-41af-91ab-2d7cd011db47"
},
"objectId": {
"value": "bc93052d-397e-4fba-b486-f5915bfd2a53"
},
"skuName": {
"value": "Standard"
},
"secretName": {
"value": "CAK"
},
"secretValue": {
"value": "b4355b9ccaf727d2ba7744ee991ce00e"
},
"secretName2": {
"value": "CKN"
},
"secretValue2": {
"value": "93e9ce8469eff0536784fc4ad253b5a6"
}
}
160 changes: 160 additions & 0 deletions src/Network/Network.Test/ScenarioTests/CreateKeyVaultTemplate.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"vaultName": {
"type": "string",
"metadata": {
"description": "Specifies the name of the key vault."
}
},
"location": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "Specifies the Azure location where the key vault should be created."
}
},
"enabledForDeployment": {
"type": "bool",
"defaultValue": true,
"allowedValues": [
true,
false
],
"metadata": {
"description": "Specifies whether Azure Virtual Machines are permitted to retrieve certificates stored as secrets from the key vault."
}
},
"enabledForDiskEncryption": {
"type": "bool",
"defaultValue": true,
"allowedValues": [
true,
false
],
"metadata": {
"description": "Specifies whether Azure Disk Encryption is permitted to retrieve secrets from the vault and unwrap keys."
}
},
"enabledForTemplateDeployment": {
"type": "bool",
"defaultValue": true,
"allowedValues": [
true,
false
],
"metadata": {
"description": "Specifies whether Azure Resource Manager is permitted to retrieve secrets from the key vault."
}
},
"tenantId": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "Specifies the Azure Active Directory tenant ID that should be used for authenticating requests to the key vault. Get it by using Get-AzSubscription cmdlet."
}
},
"objectId": {
"type": "string",
"metadata": {
"description": "Specifies the object ID of a user, service principal or security group in the Azure Active Directory tenant for the vault. The object ID must be unique for the list of access policies. Get it by using Get-AzADUser or Get-AzADServicePrincipal cmdlets."
}
},
"skuName": {
"type": "string",
"defaultValue": "Standard",
"allowedValues": [
"Standard",
"Premium"
],
"metadata": {
"description": "Specifies whether the key vault is a standard vault or a premium vault."
}
},
"secretName": {
"type": "string",
"metadata": {
"description": "Specifies the name of the secret that you want to create."
}
},
"secretValue": {
"type": "securestring",
"metadata": {
"description": "Specifies the value of the secret that you want to create."
}
},
"secretName2": {
"type": "string",
"metadata": {
"description": "Specifies the name of the secret that you want to create."
}
},
"secretValue2": {
"type": "securestring",
"metadata": {
"description": "Specifies the value of the secret that you want to create."
}
}
},
"resources": [
{
"type": "Microsoft.KeyVault/vaults",
"apiVersion": "2019-09-01",
"name": "[parameters('vaultName')]",
"location": "[parameters('location')]",
"properties": {
"enabledForDeployment": "[parameters('enabledForDeployment')]",
"enabledForDiskEncryption": "[parameters('enabledForDiskEncryption')]",
"enabledForTemplateDeployment": "[parameters('enabledForTemplateDeployment')]",
"tenantId": "[parameters('tenantId')]",
"accessPolicies": [
{
"objectId": "[parameters('objectId')]",
"tenantId": "[parameters('tenantId')]",
"permissions": {
"keys": [
"all"
],
"secrets": [
"all"
]
}
}
],
"sku": {
"name": "[parameters('skuName')]",
"family": "A"
},
"networkAcls": {
"defaultAction": "Allow",
"bypass": "AzureServices"
}
}
},
{
"type": "Microsoft.KeyVault/vaults/secrets",
"apiVersion": "2019-09-01",
"name": "[concat(parameters('vaultName'), '/', parameters('secretName'))]",
"location": "[parameters('location')]",
"dependsOn": [
"[resourceId('Microsoft.KeyVault/vaults', parameters('vaultName'))]"
],
"properties": {
"value": "[parameters('secretValue')]"
}
},
{
"type": "Microsoft.KeyVault/vaults/secrets",
"apiVersion": "2019-09-01",
"name": "[concat(parameters('vaultName'), '/', parameters('secretName2'))]",
"location": "[parameters('location')]",
"dependsOn": [
"[resourceId('Microsoft.KeyVault/vaults', parameters('vaultName'))]"
],
"properties": {
"value": "[parameters('secretValue2')]"
}
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// ----------------------------------------------------------------------------------
//
// Copyright Microsoft Corporation
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------------------------------------------------------------

using Microsoft.Azure.Commands.Network.Test.ScenarioTests;
using Microsoft.Azure.Test.HttpRecorder;
using Microsoft.Rest.ClientRuntime.Azure.TestFramework;
using Microsoft.WindowsAzure.Commands.ScenarioTest;
using Newtonsoft.Json;
using System;
using System.IO;
using Xunit;
using Xunit.Abstractions;

namespace Commands.Network.Test.ScenarioTests
{
public class ExpressRoutePortsMacSecTest : NetworkTestRunner
{
public ExpressRoutePortsMacSecTest(ITestOutputHelper output)
: base(output)
{
}

[Fact]
[Trait(Category.AcceptanceType, Category.CheckIn)]
[Trait(Category.Owner, NrpTeamAlias.pgtm)]
public void TestExpressRoutePortMacSecConfigCRUD()
{
TestRunner.RunTestScript("Test-ExpressRoutePortMacSecConfigCRUD");
}
}
}
154 changes: 154 additions & 0 deletions src/Network/Network.Test/ScenarioTests/ExpressRoutePortsMacSecTest.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
# ----------------------------------------------------------------------------------
#
# Copyright Microsoft Corporation
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ----------------------------------------------------------------------------------

function Check-CmdletReturnType
{
param($cmdletName, $cmdletReturn)

$cmdletData = Get-Command $cmdletName
Assert-NotNull $cmdletData
[array]$cmdletReturnTypes = $cmdletData.OutputType.Name | Foreach-Object { return ($_ -replace "Microsoft.Azure.Commands.Network.Models.","") }
[array]$cmdletReturnTypes = $cmdletReturnTypes | Foreach-Object { return ($_ -replace "System.","") }
$realReturnType = $cmdletReturn.GetType().Name -replace "Microsoft.Azure.Commands.Network.Models.",""
return $cmdletReturnTypes -contains $realReturnType
}

<#
.SYNOPSIS
Test creating ExpressRoutePort resource with MACsec configuration.
#>
function Test-ExpressRoutePortMacSecConfigCRUD
{

# Setup
# eastus --> Equinix-Ashburn-DC2 needed because MACsec can only be applied on juniper routers
$rgname = Get-ResourceName
$rglocation = "East US"
$rname = Get-ResourceName
$vaultName = Get-ResourceName
$identityName = Get-ResourceName
$resourceTypeParent = "Microsoft.Network/expressRoutePorts"
$location = "East US"
$peeringLocation = "Equinix-Ashburn-DC2"
$encapsulation = "QinQ"
$bandwidthInGbps = 10.0
$gcmAes128Cipher = "GcmAes128"
$cakName = "CAK"
$cknName = "CKN"
try
{
New-AzResourceGroup -Name $rgname -Location $location

# Can't assign service principal access to key vault while deploying in dev pipeline.
# Service principal needs access to secret id value
# Solution: deploy key vault via arm template with service principal whitelisted
$pathToJson = ".\..\..\..\ScenarioTests\CreateKeyVaultParameters.json"
$keyVaultParametersJson = (Get-Content $pathToJson | ConvertFrom-Json)
$keyVaultParametersJson.tenantId.value = $tenantId
$keyVaultParametersJson.vaultName.value = $vaultName
$keyVaultParametersJson.secretName.value = $cakName
$keyVaultParametersJson.secretName2.value = $cknName

# Get tenant id for service principal whitelist
$context = get-azcontext
$tenant = $context.Tenant.Id

# hard code service principal object id -- following CMD returned null locally
# $id = $context.Account.Id
$servicePrincipalObjectId = "bc93052d-397e-4fba-b486-f5915bfd2a53"

# Set service principal whitelist in ARM deployment parameters
$keyVaultParametersJson.tenantId.value = $tenant
$keyVaultParametersJson.objectId.value = $servicePrincipalObjectId
$keyVaultParametersJson | ConvertTo-Json | set-content $pathToJson

New-AzResourceGroupDeployment -Name $rgname -ResourceGroupName $rgname -TemplateParameterFile .\..\..\..\ScenarioTests\CreateKeyVaultParameters.json -TemplateFile .\..\..\..\ScenarioTests\CreateKeyVaultTemplate.json
Start-Sleep -Seconds 60

# Get key vault deployed via ARM
$keyVault = Get-AzKeyVault -VaultName $vaultName -ResourceGroupName $rgname
Assert-NotNull $keyVault

# Keyvault with CAK/CKN secrets
$MACsecCAKSecret = Get-AzKeyVaultSecret -VaultName $vaultName -Name $cakName
$MACsecCKNSecret = Get-AzKeyVaultSecret -VaultName $vaultName -Name $cknName

# Create ExpressRoutePort
$vExpressRoutePort = New-AzExpressRoutePort -ResourceGroupName $rgname -Name $rname -Location $location -PeeringLocation $peeringLocation -Encapsulation $encapsulation -BandwidthInGbps $bandwidthInGbps
Assert-NotNull $vExpressRoutePort
Assert-True { Check-CmdletReturnType "New-AzExpressRoutePort" $vExpressRoutePort }
Assert-NotNull $vExpressRoutePort.Links
Assert-True { $vExpressRoutePort.Links.Count -eq 2 }
Assert-AreEqual $rname $vExpressRoutePort.Name

# Get ExpressRoutePort
$vExpressRoutePort = Get-AzExpressRoutePort -ResourceGroupName $rgname -Name $rname
Assert-NotNull $vExpressRoutePort
Assert-True { Check-CmdletReturnType "Get-AzExpressRoutePort" $vExpressRoutePort }
Assert-AreEqual $rname $vExpressRoutePort.Name

# Create Managed Identity
$identity = New-AzUserAssignedIdentity -Name $identityName -Location $rglocation -ResourceGroup $rgname

# Set manager identity permission to keyvault
# ERPort resource needs access to secret value and id
Set-AzKeyVaultAccessPolicy -VaultName $vaultName -PermissionsToSecrets get -ObjectId $identity.PrincipalId

# Set this user identity to be used by ExpressRoute
$erIdentity = New-AzExpressRoutePortIdentity -UserAssignedIdentityId $identity.Id

# Add MACsec CAK/CKN/Cipher
$vExpressRoutePort.Links[0].MacSecConfig.CknSecretIdentifier = $MacSecCKNSecret.Id
$vExpressRoutePort.Links[0].MacSecConfig.CakSecretIdentifier = $MacSecCAKSecret.Id
$vExpressRoutePort.Links[0].MacSecConfig.Cipher = $gcmAes128Cipher
$vExpressRoutePort.Links[1].MacSecConfig.CknSecretIdentifier = $MacSecCKNSecret.Id
$vExpressRoutePort.Links[1].MacSecConfig.CakSecretIdentifier = $MacSecCAKSecret.Id
$vExpressRoutePort.Links[1].MacSecConfig.Cipher = $gcmAes128Cipher
$vExpressRoutePort.identity = $erIdentity

# Set admin state
$vExpressRoutePort.Links[0].AdminState = "Enabled"
$vExpressRoutePort.Links[1].AdminState = "Enabled"

# Apply the update
Set-AzExpressRoutePort -ExpressRoutePort $vExpressRoutePort

# List ExpressRouteLinks
$vExpressRouteLinksList = $vExpressRoutePort | Get-AzExpressRoutePortLinkConfig
Assert-True { $vExpressRouteLinksList.Count -eq 2 }

# Get ExpressRouteLink 1
$vExpressRouteLink = $vExpressRoutePort | Get-AzExpressRoutePortLinkConfig -Name "Link1"
Assert-NotNull $vExpressRouteLink;
Assert-AreEqual $vExpressRouteLink.AdminState "Enabled"
Assert-AreEqual $vExpressRouteLink.MacSecConfig.Cipher $gcmAes128Cipher
Assert-Null $vExpressRouteLink.MacSecConfig.SciState

# Get ExpressRouteLink 2
$vExpressRouteLink = $vExpressRoutePort | Get-AzExpressRoutePortLinkConfig -Name "Link2"
Assert-NotNull $vExpressRouteLink;
Assert-AreEqual $vExpressRouteLink.AdminState "Enabled"
Assert-AreEqual $vExpressRouteLink.MacSecConfig.Cipher $gcmAes128Cipher
Assert-Null $vExpressRouteLink.MacSecConfig.SciState

# Remove ExpressRoutePort
$removeExpressRoutePort = Remove-AzExpressRoutePort -ResourceGroupName $rgname -Name $rname -PassThru -Force
Assert-AreEqual $true $removeExpressRoutePort
}
finally
{
# Cleanup
Clean-ResourceGroup $rgname
}
}
Loading

0 comments on commit 23694e8

Please sign in to comment.