support to declaratively set attestation policy

This commit is contained in:
Moritz Sanft 2023-06-21 11:45:13 +02:00
parent b25228d175
commit dbc495f164
15 changed files with 82 additions and 188 deletions

View File

@ -4,11 +4,11 @@ load("//bazel/go:go_test.bzl", "go_test")
go_library( go_library(
name = "cloudcmd", name = "cloudcmd",
srcs = [ srcs = [
"attestationpolicy.go",
"clients.go", "clients.go",
"cloudcmd.go", "cloudcmd.go",
"create.go", "create.go",
"iam.go", "iam.go",
"patch.go",
"rollback.go", "rollback.go",
"terminate.go", "terminate.go",
"validators.go", "validators.go",
@ -29,9 +29,6 @@ go_library(
"//internal/config", "//internal/config",
"//internal/constants", "//internal/constants",
"//internal/imagefetcher", "//internal/imagefetcher",
"@com_github_azure_azure_sdk_for_go//profiles/latest/attestation/attestation",
"@com_github_azure_azure_sdk_for_go_sdk_azcore//policy",
"@com_github_azure_azure_sdk_for_go_sdk_azidentity//:azidentity",
"@com_github_hashicorp_terraform_json//:terraform-json", "@com_github_hashicorp_terraform_json//:terraform-json",
"@com_github_spf13_cobra//:cobra", "@com_github_spf13_cobra//:cobra",
], ],
@ -40,10 +37,10 @@ go_library(
go_test( go_test(
name = "cloudcmd_test", name = "cloudcmd_test",
srcs = [ srcs = [
"attestationpolicy_test.go",
"clients_test.go", "clients_test.go",
"create_test.go", "create_test.go",
"iam_test.go", "iam_test.go",
"patch_test.go",
"rollback_test.go", "rollback_test.go",
"terminate_test.go", "terminate_test.go",
"validators_test.go", "validators_test.go",

View File

@ -0,0 +1,54 @@
/*
Copyright (c) Edgeless Systems GmbH
SPDX-License-Identifier: AGPL-3.0-only
*/
package cloudcmd
import (
"encoding/base64"
"fmt"
)
// maaAttestationPolicy is the default attestation policy for Azure VMs on Constellation.
const maaAttestationPolicy = `
version= 1.0;
authorizationrules
{
[type=="x-ms-azurevm-default-securebootkeysvalidated", value==false] => deny();
[type=="x-ms-azurevm-debuggersdisabled", value==false] => deny();
// The line below was edited by the Constellation CLI. Do not edit manually.
//[type=="secureboot", value==false] => deny();
[type=="x-ms-azurevm-signingdisabled", value==false] => deny();
[type=="x-ms-azurevm-dbvalidated", value==false] => deny();
[type=="x-ms-azurevm-dbxvalidated", value==false] => deny();
=> permit();
};
issuancerules
{
};`
// NewAzureMaaAttestationPolicy returns a new AzureAttestationPolicy to use with MAA.
func NewAzureMaaAttestationPolicy() AzureAttestationPolicy {
return AzureAttestationPolicy{
policy: maaAttestationPolicy,
}
}
// AzureAttestationPolicy patches attestation policies on Azure.
type AzureAttestationPolicy struct {
policy string
}
// Encode encodes the base64-encoded attestation policy in the JWS format specified here:
// https://learn.microsoft.com/en-us/azure/attestation/author-sign-policy#creating-the-policy-file-in-json-web-signature-format
func (p AzureAttestationPolicy) Encode() string {
encodedPolicy := base64.RawURLEncoding.EncodeToString([]byte(p.policy))
const header = `{"alg":"none"}`
payload := fmt.Sprintf(`{"AttestationPolicy":"%s"}`, encodedPolicy)
encodedHeader := base64.RawURLEncoding.EncodeToString([]byte(header))
encodedPayload := base64.RawURLEncoding.EncodeToString([]byte(payload))
return fmt.Sprintf("%s.%s.", encodedHeader, encodedPayload)
}

View File

@ -11,12 +11,12 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func TestEncodeAttestationPolicy(t *testing.T) { func TestAzureMaaAttestationPolicyEncode(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
p := AzurePolicyPatcher{} p := NewAzureMaaAttestationPolicy()
// taken from <resource group url in the azure portal>/providers/Microsoft.Attestation/attestationProviders/<attestation provider name>/mrsg_item2 // taken from <resource group url in the azure portal>/providers/Microsoft.Attestation/attestationProviders/<attestation provider name>/mrsg_item2
expected := "eyJhbGciOiJub25lIn0.eyJBdHRlc3RhdGlvblBvbGljeSI6IkNpQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNCMlpYSnphVzl1UFNBeExqQTdDaUFnSUNBZ0lDQWdJQ0FnSUNBZ0lDQmhkWFJvYjNKcGVtRjBhVzl1Y25Wc1pYTUtJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lIc0tJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0JiZEhsd1pUMDlJbmd0YlhNdFlYcDFjbVYyYlMxa1pXWmhkV3gwTFhObFkzVnlaV0p2YjNSclpYbHpkbUZzYVdSaGRHVmtJaXdnZG1Gc2RXVTlQV1poYkhObFhTQTlQaUJrWlc1NUtDazdDaUFnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnVzNSNWNHVTlQU0o0TFcxekxXRjZkWEpsZG0wdFpHVmlkV2RuWlhKelpHbHpZV0pzWldRaUxDQjJZV3gxWlQwOVptRnNjMlZkSUQwLUlHUmxibmtvS1RzS0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQXZMeUJVYUdVZ2JHbHVaU0JpWld4dmR5QjNZWE1nWldScGRHVmtJR0o1SUhSb1pTQkRiMjV6ZEdWc2JHRjBhVzl1SUVOTVNTNGdSRzhnYm05MElHVmthWFFnYldGdWRXRnNiSGt1Q2lBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0x5OWJkSGx3WlQwOUluTmxZM1Z5WldKdmIzUWlMQ0IyWVd4MVpUMDlabUZzYzJWZElEMC1JR1JsYm5rb0tUc0tJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0JiZEhsd1pUMDlJbmd0YlhNdFlYcDFjbVYyYlMxemFXZHVhVzVuWkdsellXSnNaV1FpTENCMllXeDFaVDA5Wm1Gc2MyVmRJRDAtSUdSbGJua29LVHNLSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNCYmRIbHdaVDA5SW5ndGJYTXRZWHAxY21WMmJTMWtZblpoYkdsa1lYUmxaQ0lzSUhaaGJIVmxQVDFtWVd4elpWMGdQVDRnWkdWdWVTZ3BPd29nSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUZ0MGVYQmxQVDBpZUMxdGN5MWhlblZ5WlhadExXUmllSFpoYkdsa1lYUmxaQ0lzSUhaaGJIVmxQVDFtWVd4elpWMGdQVDRnWkdWdWVTZ3BPd29nSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUQwLUlIQmxjbTFwZENncE93b2dJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ2ZUc0tJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lHbHpjM1ZoYm1ObGNuVnNaWE1LSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJSHNLSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJSDA3In0." expected := "eyJhbGciOiJub25lIn0.eyJBdHRlc3RhdGlvblBvbGljeSI6IkNpQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNCMlpYSnphVzl1UFNBeExqQTdDaUFnSUNBZ0lDQWdJQ0FnSUNBZ0lDQmhkWFJvYjNKcGVtRjBhVzl1Y25Wc1pYTUtJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lIc0tJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0JiZEhsd1pUMDlJbmd0YlhNdFlYcDFjbVYyYlMxa1pXWmhkV3gwTFhObFkzVnlaV0p2YjNSclpYbHpkbUZzYVdSaGRHVmtJaXdnZG1Gc2RXVTlQV1poYkhObFhTQTlQaUJrWlc1NUtDazdDaUFnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnVzNSNWNHVTlQU0o0TFcxekxXRjZkWEpsZG0wdFpHVmlkV2RuWlhKelpHbHpZV0pzWldRaUxDQjJZV3gxWlQwOVptRnNjMlZkSUQwLUlHUmxibmtvS1RzS0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQXZMeUJVYUdVZ2JHbHVaU0JpWld4dmR5QjNZWE1nWldScGRHVmtJR0o1SUhSb1pTQkRiMjV6ZEdWc2JHRjBhVzl1SUVOTVNTNGdSRzhnYm05MElHVmthWFFnYldGdWRXRnNiSGt1Q2lBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0x5OWJkSGx3WlQwOUluTmxZM1Z5WldKdmIzUWlMQ0IyWVd4MVpUMDlabUZzYzJWZElEMC1JR1JsYm5rb0tUc0tJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0JiZEhsd1pUMDlJbmd0YlhNdFlYcDFjbVYyYlMxemFXZHVhVzVuWkdsellXSnNaV1FpTENCMllXeDFaVDA5Wm1Gc2MyVmRJRDAtSUdSbGJua29LVHNLSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNCYmRIbHdaVDA5SW5ndGJYTXRZWHAxY21WMmJTMWtZblpoYkdsa1lYUmxaQ0lzSUhaaGJIVmxQVDFtWVd4elpWMGdQVDRnWkdWdWVTZ3BPd29nSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUZ0MGVYQmxQVDBpZUMxdGN5MWhlblZ5WlhadExXUmllSFpoYkdsa1lYUmxaQ0lzSUhaaGJIVmxQVDFtWVd4elpWMGdQVDRnWkdWdWVTZ3BPd29nSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUQwLUlIQmxjbTFwZENncE93b2dJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ2ZUc0tJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lHbHpjM1ZoYm1ObGNuVnNaWE1LSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJSHNLSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJSDA3In0."
assert.Equal(expected, p.encodeAttestationPolicy()) assert.Equal(expected, p.Encode())
} }

View File

@ -35,7 +35,6 @@ type Creator struct {
newTerraformClient func(ctx context.Context) (terraformClient, error) newTerraformClient func(ctx context.Context) (terraformClient, error)
newLibvirtRunner func() libvirtRunner newLibvirtRunner func() libvirtRunner
newRawDownloader func() rawDownloader newRawDownloader func() rawDownloader
policyPatcher policyPatcher
} }
// NewCreator creates a new creator. // NewCreator creates a new creator.
@ -52,7 +51,6 @@ func NewCreator(out io.Writer) *Creator {
newRawDownloader: func() rawDownloader { newRawDownloader: func() rawDownloader {
return imagefetcher.NewDownloader() return imagefetcher.NewDownloader()
}, },
policyPatcher: NewAzurePolicyPatcher(),
} }
} }
@ -226,6 +224,7 @@ func (c *Creator) createAzure(ctx context.Context, cl terraformClient, opts Crea
ImageID: opts.image, ImageID: opts.image,
SecureBoot: *opts.Config.Provider.Azure.SecureBoot, SecureBoot: *opts.Config.Provider.Azure.SecureBoot,
CreateMAA: opts.Config.GetAttestationConfig().GetVariant().Equal(variant.AzureSEVSNP{}), CreateMAA: opts.Config.GetAttestationConfig().GetVariant().Equal(variant.AzureSEVSNP{}),
MAAPolicy: NewAzureMaaAttestationPolicy().Encode(),
Debug: opts.Config.IsDebugCluster(), Debug: opts.Config.IsDebugCluster(),
} }
@ -243,13 +242,6 @@ func (c *Creator) createAzure(ctx context.Context, cl terraformClient, opts Crea
return clusterid.File{}, err return clusterid.File{}, err
} }
if vars.CreateMAA {
// Patch the attestation policy to allow the cluster to boot while having secure boot disabled.
if err := c.policyPatcher.Patch(ctx, tfOutput.AttestationURL); err != nil {
return clusterid.File{}, err
}
}
return clusterid.File{ return clusterid.File{
CloudProvider: cloudprovider.Azure, CloudProvider: cloudprovider.Azure,
IP: tfOutput.IP, IP: tfOutput.IP,
@ -259,11 +251,6 @@ func (c *Creator) createAzure(ctx context.Context, cl terraformClient, opts Crea
}, nil }, nil
} }
// policyPatcher interacts with the CSP (currently only applies for Azure) to update the attestation policy.
type policyPatcher interface {
Patch(ctx context.Context, attestationURL string) error
}
// The azurerm Terraform provider enforces its own convention of case sensitivity for Azure URIs which Azure's API itself does not enforce or, even worse, actually returns. // The azurerm Terraform provider enforces its own convention of case sensitivity for Azure URIs which Azure's API itself does not enforce or, even worse, actually returns.
// Let's go loco with case insensitive Regexp here and fix the user input here to be compliant with this arbitrary design decision. // Let's go loco with case insensitive Regexp here and fix the user input here to be compliant with this arbitrary design decision.
var ( var (

View File

@ -33,7 +33,6 @@ func TestCreator(t *testing.T) {
libvirt *stubLibvirtRunner libvirt *stubLibvirtRunner
provider cloudprovider.Provider provider cloudprovider.Provider
config *config.Config config *config.Config
policyPatcher *stubPolicyPatcher
wantErr bool wantErr bool
wantRollback bool // Use only together with stubClients. wantRollback bool // Use only together with stubClients.
wantTerraformRollback bool // When libvirt fails, don't call into Terraform. wantTerraformRollback bool // When libvirt fails, don't call into Terraform.
@ -65,7 +64,6 @@ func TestCreator(t *testing.T) {
cfg.RemoveProviderAndAttestationExcept(cloudprovider.Azure) cfg.RemoveProviderAndAttestationExcept(cloudprovider.Azure)
return cfg return cfg
}(), }(),
policyPatcher: &stubPolicyPatcher{},
}, },
"azure trusted launch": { "azure trusted launch": {
tfClient: &stubTerraformClient{ip: ip}, tfClient: &stubTerraformClient{ip: ip},
@ -77,18 +75,6 @@ func TestCreator(t *testing.T) {
} }
return cfg return cfg
}(), }(),
policyPatcher: &stubPolicyPatcher{},
},
"azure new policy patch error": {
tfClient: &stubTerraformClient{ip: ip},
provider: cloudprovider.Azure,
config: func() *config.Config {
cfg := config.Default()
cfg.RemoveProviderAndAttestationExcept(cloudprovider.Azure)
return cfg
}(),
policyPatcher: &stubPolicyPatcher{someErr},
wantErr: true,
}, },
"azure newTerraformClient error": { "azure newTerraformClient error": {
newTfClientErr: someErr, newTfClientErr: someErr,
@ -98,7 +84,6 @@ func TestCreator(t *testing.T) {
cfg.RemoveProviderAndAttestationExcept(cloudprovider.Azure) cfg.RemoveProviderAndAttestationExcept(cloudprovider.Azure)
return cfg return cfg
}(), }(),
policyPatcher: &stubPolicyPatcher{},
wantErr: true, wantErr: true,
}, },
"azure create cluster error": { "azure create cluster error": {
@ -109,7 +94,6 @@ func TestCreator(t *testing.T) {
cfg.RemoveProviderAndAttestationExcept(cloudprovider.Azure) cfg.RemoveProviderAndAttestationExcept(cloudprovider.Azure)
return cfg return cfg
}(), }(),
policyPatcher: &stubPolicyPatcher{},
wantErr: true, wantErr: true,
wantRollback: true, wantRollback: true,
wantTerraformRollback: true, wantTerraformRollback: true,
@ -213,7 +197,6 @@ func TestCreator(t *testing.T) {
destination: "some-destination", destination: "some-destination",
} }
}, },
policyPatcher: tc.policyPatcher,
} }
opts := CreateOptions{ opts := CreateOptions{
@ -247,14 +230,6 @@ func TestCreator(t *testing.T) {
} }
} }
type stubPolicyPatcher struct {
patchErr error
}
func (s stubPolicyPatcher) Patch(_ context.Context, _ string) error {
return s.patchErr
}
func TestNormalizeAzureURIs(t *testing.T) { func TestNormalizeAzureURIs(t *testing.T) {
testCases := map[string]struct { testCases := map[string]struct {
in terraform.AzureClusterVariables in terraform.AzureClusterVariables

View File

@ -1,94 +0,0 @@
/*
Copyright (c) Edgeless Systems GmbH
SPDX-License-Identifier: AGPL-3.0-only
*/
package cloudcmd
import (
"context"
"encoding/base64"
"fmt"
"net/http"
"github.com/Azure/azure-sdk-for-go/profiles/latest/attestation/attestation"
azpolicy "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
)
// NewAzurePolicyPatcher returns a new AzurePolicyPatcher.
func NewAzurePolicyPatcher() AzurePolicyPatcher {
return AzurePolicyPatcher{}
}
// AzurePolicyPatcher patches attestation policies on Azure.
type AzurePolicyPatcher struct{}
// Patch updates the attestation policy to the base64-encoded attestation policy JWT for the given attestation URL.
// https://learn.microsoft.com/en-us/azure/attestation/author-sign-policy#next-steps
func (p AzurePolicyPatcher) Patch(ctx context.Context, attestationURL string) error {
// hacky way to update the MAA attestation policy. This should be changed as soon as either the Terraform provider supports it
// or the Go SDK gets updated to a recent API version.
// https://github.com/hashicorp/terraform-provider-azurerm/issues/20804
cred, err := azidentity.NewDefaultAzureCredential(nil)
if err != nil {
return fmt.Errorf("retrieving default Azure credentials: %w", err)
}
token, err := cred.GetToken(ctx, azpolicy.TokenRequestOptions{
Scopes: []string{"https://attest.azure.net/.default"},
})
if err != nil {
return fmt.Errorf("retrieving token from default Azure credentials: %w", err)
}
client := attestation.NewPolicyClient()
// azureGuest is the id for the "Azure VM" attestation type. Other types are documented here:
// https://learn.microsoft.com/en-us/rest/api/attestation/policy/set
req, err := client.SetPreparer(ctx, attestationURL, "azureGuest", p.encodeAttestationPolicy())
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token.Token))
if err != nil {
return fmt.Errorf("preparing request: %w", err)
}
resp, err := client.Send(req)
if err != nil {
return fmt.Errorf("sending request: %w", err)
}
resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("updating attestation policy: unexpected status code: %s", resp.Status)
}
return nil
}
// encodeAttestationPolicy encodes the base64-encoded attestation policy in the JWS format specified here:
// https://learn.microsoft.com/en-us/azure/attestation/author-sign-policy#creating-the-policy-file-in-json-web-signature-format
func (p AzurePolicyPatcher) encodeAttestationPolicy() string {
const policy = `
version= 1.0;
authorizationrules
{
[type=="x-ms-azurevm-default-securebootkeysvalidated", value==false] => deny();
[type=="x-ms-azurevm-debuggersdisabled", value==false] => deny();
// The line below was edited by the Constellation CLI. Do not edit manually.
//[type=="secureboot", value==false] => deny();
[type=="x-ms-azurevm-signingdisabled", value==false] => deny();
[type=="x-ms-azurevm-dbvalidated", value==false] => deny();
[type=="x-ms-azurevm-dbxvalidated", value==false] => deny();
=> permit();
};
issuancerules
{
};`
encodedPolicy := base64.RawURLEncoding.EncodeToString([]byte(policy))
const header = `{"alg":"none"}`
payload := fmt.Sprintf(`{"AttestationPolicy":"%s"}`, encodedPolicy)
encodedHeader := base64.RawURLEncoding.EncodeToString([]byte(header))
encodedPayload := base64.RawURLEncoding.EncodeToString([]byte(payload))
return fmt.Sprintf("%s.%s.", encodedHeader, encodedPayload)
}

View File

@ -14,6 +14,7 @@ import (
"strings" "strings"
"time" "time"
"github.com/edgelesssys/constellation/v2/cli/internal/cloudcmd"
"github.com/edgelesssys/constellation/v2/cli/internal/clusterid" "github.com/edgelesssys/constellation/v2/cli/internal/clusterid"
"github.com/edgelesssys/constellation/v2/cli/internal/helm" "github.com/edgelesssys/constellation/v2/cli/internal/helm"
"github.com/edgelesssys/constellation/v2/cli/internal/kubernetes" "github.com/edgelesssys/constellation/v2/cli/internal/kubernetes"
@ -253,6 +254,7 @@ func parseTerraformUpgradeVars(cmd *cobra.Command, conf *config.Config, fetcher
ImageID: imageRef, ImageID: imageRef,
SecureBoot: *conf.Provider.Azure.SecureBoot, SecureBoot: *conf.Provider.Azure.SecureBoot,
CreateMAA: conf.GetAttestationConfig().GetVariant().Equal(variant.AzureSEVSNP{}), CreateMAA: conf.GetAttestationConfig().GetVariant().Equal(variant.AzureSEVSNP{}),
MAAPolicy: cloudcmd.NewAzureMaaAttestationPolicy().Encode(),
Debug: conf.IsDebugCluster(), Debug: conf.IsDebugCluster(),
} }
return targets, vars, nil return targets, vars, nil

View File

@ -51,6 +51,7 @@ resource "azurerm_attestation_provider" "attestation_provider" {
name = format("constell%s", local.uid) name = format("constell%s", local.uid)
resource_group_name = var.resource_group resource_group_name = var.resource_group
location = var.location location = var.location
azure_vm_policy_base64 = var.maa_policy
lifecycle { lifecycle {
# Attestation policies will be set automatically upon creation, even if not specified in the resource, # Attestation policies will be set automatically upon creation, even if not specified in the resource,
@ -58,7 +59,7 @@ resource "azurerm_attestation_provider" "attestation_provider" {
# To prevent them from being set to null when applying an upgrade, ignore the changes until the issue # To prevent them from being set to null when applying an upgrade, ignore the changes until the issue
# is resolved by Azure. # is resolved by Azure.
# Related issue: https://github.com/hashicorp/terraform-provider-azurerm/issues/21998 # Related issue: https://github.com/hashicorp/terraform-provider-azurerm/issues/21998
ignore_changes = [open_enclave_policy_base64, sgx_enclave_policy_base64, tpm_policy_base64] ignore_changes = [open_enclave_policy_base64, sgx_enclave_policy_base64, tpm_policy_base64, azure_vm_policy_base64, sev_snp_policy_base64]
} }
} }

View File

@ -69,6 +69,11 @@ variable "create_maa" {
description = "Whether to create a Microsoft Azure attestation provider." description = "Whether to create a Microsoft Azure attestation provider."
} }
variable "maa_policy" {
type = string
description = "Base64-encoded Attestation policy for the Microsoft Azure attestation provider."
}
variable "debug" { variable "debug" {
type = bool type = bool
default = false default = false

View File

@ -183,6 +183,8 @@ type AzureClusterVariables struct {
SecureBoot bool SecureBoot bool
// CreateMAA sets whether a Microsoft Azure attestation provider should be created. // CreateMAA sets whether a Microsoft Azure attestation provider should be created.
CreateMAA bool CreateMAA bool
// MAAPolicy sets the base64-encoded policy for the Microsoft Azure attestation provider.
MAAPolicy string
// Debug is true if debug mode is enabled. // Debug is true if debug mode is enabled.
Debug bool Debug bool
} }
@ -200,6 +202,7 @@ func (v *AzureClusterVariables) String() string {
writeLinef(b, "confidential_vm = %t", v.ConfidentialVM) writeLinef(b, "confidential_vm = %t", v.ConfidentialVM)
writeLinef(b, "secure_boot = %t", v.SecureBoot) writeLinef(b, "secure_boot = %t", v.SecureBoot)
writeLinef(b, "create_maa = %t", v.CreateMAA) writeLinef(b, "create_maa = %t", v.CreateMAA)
writeLinef(b, "maa_policy = %q", v.MAAPolicy)
writeLinef(b, "debug = %t", v.Debug) writeLinef(b, "debug = %t", v.Debug)
return b.String() return b.String()

View File

@ -10,7 +10,6 @@ go_library(
importpath = "github.com/edgelesssys/constellation/v2/cli/internal/upgrade", importpath = "github.com/edgelesssys/constellation/v2/cli/internal/upgrade",
visibility = ["//cli:__subpackages__"], visibility = ["//cli:__subpackages__"],
deps = [ deps = [
"//cli/internal/cloudcmd",
"//cli/internal/clusterid", "//cli/internal/clusterid",
"//cli/internal/terraform", "//cli/internal/terraform",
"//internal/cloud/cloudprovider", "//internal/cloud/cloudprovider",

View File

@ -14,7 +14,6 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
"github.com/edgelesssys/constellation/v2/cli/internal/cloudcmd"
"github.com/edgelesssys/constellation/v2/cli/internal/clusterid" "github.com/edgelesssys/constellation/v2/cli/internal/clusterid"
"github.com/edgelesssys/constellation/v2/cli/internal/terraform" "github.com/edgelesssys/constellation/v2/cli/internal/terraform"
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider" "github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
@ -26,7 +25,6 @@ import (
func NewTerraformUpgrader(tfClient tfClient, outWriter io.Writer) (*TerraformUpgrader, error) { func NewTerraformUpgrader(tfClient tfClient, outWriter io.Writer) (*TerraformUpgrader, error) {
return &TerraformUpgrader{ return &TerraformUpgrader{
tf: tfClient, tf: tfClient,
policyPatcher: cloudcmd.NewAzurePolicyPatcher(),
outWriter: outWriter, outWriter: outWriter,
}, nil }, nil
} }
@ -34,7 +32,6 @@ func NewTerraformUpgrader(tfClient tfClient, outWriter io.Writer) (*TerraformUpg
// TerraformUpgrader is responsible for performing Terraform migrations on cluster upgrades. // TerraformUpgrader is responsible for performing Terraform migrations on cluster upgrades.
type TerraformUpgrader struct { type TerraformUpgrader struct {
tf tfClient tf tfClient
policyPatcher policyPatcher
outWriter io.Writer outWriter io.Writer
} }
@ -132,7 +129,7 @@ func (u *TerraformUpgrader) CleanUpTerraformMigrations(fileHandler file.Handler,
return nil return nil
} }
// ApplyTerraformMigrations applies the migerations planned by PlanTerraformMigrations. // ApplyTerraformMigrations applies the migrations planned by PlanTerraformMigrations.
// If PlanTerraformMigrations has not been executed before, it will return an error. // If PlanTerraformMigrations has not been executed before, it will return an error.
// In case of a successful upgrade, the output will be written to the specified file and the old Terraform directory is replaced // In case of a successful upgrade, the output will be written to the specified file and the old Terraform directory is replaced
// By the new one. // By the new one.
@ -142,13 +139,6 @@ func (u *TerraformUpgrader) ApplyTerraformMigrations(ctx context.Context, fileHa
return fmt.Errorf("terraform apply: %w", err) return fmt.Errorf("terraform apply: %w", err)
} }
// AttestationURL is only set for Azure.
if tfOutput.AttestationURL != "" {
if err := u.policyPatcher.Patch(ctx, tfOutput.AttestationURL); err != nil {
return fmt.Errorf("patching policies: %w", err)
}
}
outputFileContents := clusterid.File{ outputFileContents := clusterid.File{
CloudProvider: opts.CSP, CloudProvider: opts.CSP,
InitSecret: []byte(tfOutput.Secret), InitSecret: []byte(tfOutput.Secret),

2
go.mod
View File

@ -44,7 +44,6 @@ require (
cloud.google.com/go/logging v1.7.0 cloud.google.com/go/logging v1.7.0
cloud.google.com/go/secretmanager v1.10.1 cloud.google.com/go/secretmanager v1.10.1
cloud.google.com/go/storage v1.30.1 cloud.google.com/go/storage v1.30.1
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.0 github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.0
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.2 github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.2
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.12.0 github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.12.0
@ -125,6 +124,7 @@ require (
require ( require (
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1 // indirect github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1 // indirect
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible // indirect
github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 // indirect github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 // indirect
github.com/agext/levenshtein v1.2.1 // indirect github.com/agext/levenshtein v1.2.1 // indirect
github.com/cloudflare/circl v1.3.3 // indirect github.com/cloudflare/circl v1.3.3 // indirect

View File

@ -62,7 +62,6 @@ require (
cloud.google.com/go/compute/metadata v0.2.3 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect
code.cloudfoundry.org/clock v0.0.0-20180518195852-02e53af36e6c // indirect code.cloudfoundry.org/clock v0.0.0-20180518195852-02e53af36e6c // indirect
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1 // indirect github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1 // indirect
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible // indirect
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.2 // indirect github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.2 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 // indirect
@ -70,13 +69,6 @@ require (
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v4 v4.2.1 // indirect github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v4 v4.2.1 // indirect
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v2 v2.2.1 // indirect github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v2 v2.2.1 // indirect
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
github.com/Azure/go-autorest/autorest v0.11.29 // indirect
github.com/Azure/go-autorest/autorest/adal v0.9.22 // indirect
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
github.com/Azure/go-autorest/autorest/validation v0.3.1 // indirect
github.com/Azure/go-autorest/logger v0.2.1 // indirect
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v0.9.0 // indirect github.com/AzureAD/microsoft-authentication-library-for-go v0.9.0 // indirect
github.com/BurntSushi/toml v1.2.1 // indirect github.com/BurntSushi/toml v1.2.1 // indirect
github.com/MakeNowJust/heredoc v1.0.0 // indirect github.com/MakeNowJust/heredoc v1.0.0 // indirect

View File

@ -83,7 +83,6 @@ github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiU
github.com/Azure/azure-sdk-for-go v29.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go v29.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/azure-sdk-for-go v30.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go v30.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU= github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU=
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.0 h1:8kDqDngH+DmVBiCtIjCFTGa7MBnsIOkF9IccInFEbjk= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.0 h1:8kDqDngH+DmVBiCtIjCFTGa7MBnsIOkF9IccInFEbjk=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.0/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.0/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.2 h1:uqM+VoHjVH6zdlkLF2b6O0ZANcHoj3rO0PoQ3jglUJA= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.2 h1:uqM+VoHjVH6zdlkLF2b6O0ZANcHoj3rO0PoQ3jglUJA=
@ -105,23 +104,8 @@ github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOEl
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/Azure/go-autorest v12.0.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest v12.0.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs=
github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
github.com/Azure/go-autorest/autorest v0.11.29 h1:I4+HL/JDvErx2LjyzaVxllw2lRDB5/BT2Bm4g20iqYw= github.com/Azure/go-autorest/autorest v0.11.29 h1:I4+HL/JDvErx2LjyzaVxllw2lRDB5/BT2Bm4g20iqYw=
github.com/Azure/go-autorest/autorest v0.11.29/go.mod h1:ZtEzC4Jy2JDrZLxvWs8LrBWEBycl1hbT1eknI8MtfAs=
github.com/Azure/go-autorest/autorest/adal v0.9.22 h1:/GblQdIudfEM3AWWZ0mrYJQSd7JS4S/Mbzh6F0ov0Xc=
github.com/Azure/go-autorest/autorest/adal v0.9.22/go.mod h1:XuAbAEUv2Tta//+voMI038TrJBqjKam0me7qR+L8Cmk=
github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw=
github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74=
github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
github.com/Azure/go-autorest/autorest/mocks v0.4.2 h1:PGN4EDXnuQbojHbU0UWoNvmu9AGVwYHG9/fkDYhtAfw=
github.com/Azure/go-autorest/autorest/mocks v0.4.2/go.mod h1:Vy7OitM9Kei0i1Oj+LvyAWMXJHeKH1MVlzFugfVrmyU=
github.com/Azure/go-autorest/autorest/to v0.4.0 h1:oXVqrxakqqV1UZdSazDOPOLvOIz+XA683u8EctwboHk= github.com/Azure/go-autorest/autorest/to v0.4.0 h1:oXVqrxakqqV1UZdSazDOPOLvOIz+XA683u8EctwboHk=
github.com/Azure/go-autorest/autorest/validation v0.3.1 h1:AgyqjAd94fwNAoTjl/WQXg4VvFeRFpO+UhNyRXqF1ac=
github.com/Azure/go-autorest/autorest/validation v0.3.1/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E=
github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg=
github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo=
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
github.com/AzureAD/microsoft-authentication-library-for-go v0.9.0 h1:UE9n9rkJF62ArLb1F3DEjRt8O3jLwMWdSoypKV4f3MU= github.com/AzureAD/microsoft-authentication-library-for-go v0.9.0 h1:UE9n9rkJF62ArLb1F3DEjRt8O3jLwMWdSoypKV4f3MU=
github.com/AzureAD/microsoft-authentication-library-for-go v0.9.0/go.mod h1:kgDmCTgBzIEPFElEF+FK0SdjAor06dRq2Go927dnQ6o= github.com/AzureAD/microsoft-authentication-library-for-go v0.9.0/go.mod h1:kgDmCTgBzIEPFElEF+FK0SdjAor06dRq2Go927dnQ6o=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
@ -591,7 +575,6 @@ github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXP
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=