mirror of
https://github.com/edgelesssys/constellation.git
synced 2025-05-17 13:40:22 -04:00
terraform-provider: add attestation data source (#2640)
Signed-off-by: Daniel Weiße <dw@edgeless.systems> Co-authored-by: Daniel Weiße <dw@edgeless.systems>
This commit is contained in:
parent
03c5692fdd
commit
a2de1d23ec
18 changed files with 871 additions and 177 deletions
|
@ -4,6 +4,7 @@ load("//bazel/go:go_test.bzl", "go_test")
|
|||
go_library(
|
||||
name = "provider",
|
||||
srcs = [
|
||||
"attestation_data_source.go",
|
||||
"example_resource.go",
|
||||
"image_data_source.go",
|
||||
"provider.go",
|
||||
|
@ -11,9 +12,13 @@ go_library(
|
|||
importpath = "github.com/edgelesssys/constellation/v2/terraform-provider-constellation/internal/provider",
|
||||
visibility = ["//terraform-provider-constellation:__subpackages__"],
|
||||
deps = [
|
||||
"//internal/api/attestationconfigapi",
|
||||
"//internal/attestation/measurements",
|
||||
"//internal/attestation/variant",
|
||||
"//internal/cloud/cloudprovider",
|
||||
"//internal/config",
|
||||
"//internal/imagefetcher",
|
||||
"//internal/sigstore",
|
||||
"//terraform-provider-constellation/internal/data",
|
||||
"@com_github_hashicorp_terraform_plugin_framework//datasource",
|
||||
"@com_github_hashicorp_terraform_plugin_framework//datasource/schema",
|
||||
|
@ -35,6 +40,7 @@ go_library(
|
|||
go_test(
|
||||
name = "provider_test",
|
||||
srcs = [
|
||||
"attestation_data_source_test.go",
|
||||
"image_data_source_test.go",
|
||||
"provider_test.go",
|
||||
],
|
||||
|
|
|
@ -0,0 +1,306 @@
|
|||
/*
|
||||
Copyright (c) Edgeless Systems GmbH
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package provider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/attestationconfigapi"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/variant"
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
"github.com/edgelesssys/constellation/v2/internal/sigstore"
|
||||
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
|
||||
"github.com/hashicorp/terraform-plugin-framework/datasource"
|
||||
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
|
||||
"github.com/hashicorp/terraform-plugin-framework/path"
|
||||
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
"github.com/hashicorp/terraform-plugin-log/tflog"
|
||||
)
|
||||
|
||||
// Ensure provider defined types fully satisfy framework interfaces.
|
||||
var _ datasource.DataSource = &AttestationDataSource{}
|
||||
|
||||
// NewAttestationDataSource creates a new attestation data source.
|
||||
func NewAttestationDataSource() datasource.DataSource {
|
||||
return &AttestationDataSource{}
|
||||
}
|
||||
|
||||
// AttestationDataSource defines the data source implementation.
|
||||
type AttestationDataSource struct {
|
||||
client *http.Client
|
||||
fetcher attestationconfigapi.Fetcher
|
||||
rekor *sigstore.Rekor
|
||||
}
|
||||
|
||||
// AttestationDataSourceModel describes the data source data model.
|
||||
type AttestationDataSourceModel struct {
|
||||
CSP types.String `tfsdk:"csp"`
|
||||
AttestationVariant types.String `tfsdk:"attestation_variant"`
|
||||
ImageVersion types.String `tfsdk:"image_version"`
|
||||
MaaURL types.String `tfsdk:"maa_url"`
|
||||
ID types.String `tfsdk:"id"`
|
||||
Measurements types.Map `tfsdk:"measurements"`
|
||||
Attestation types.Object `tfsdk:"attestation"`
|
||||
}
|
||||
|
||||
// Configure configures the data source.
|
||||
func (d *AttestationDataSource) Configure(_ context.Context, _ datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
|
||||
d.client = http.DefaultClient
|
||||
d.fetcher = attestationconfigapi.NewFetcher()
|
||||
rekor, err := sigstore.NewRekor()
|
||||
if err != nil {
|
||||
resp.Diagnostics.AddError("constructing rekor client", err.Error())
|
||||
return
|
||||
}
|
||||
d.rekor = rekor
|
||||
}
|
||||
|
||||
// Metadata returns the metadata for the data source.
|
||||
func (d *AttestationDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
|
||||
resp.TypeName = req.ProviderTypeName + "_attestation"
|
||||
}
|
||||
|
||||
// Schema returns the schema for the data source.
|
||||
func (d *AttestationDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
|
||||
resp.Schema = schema.Schema{
|
||||
// This description is used by the documentation generator and the language server.
|
||||
MarkdownDescription: "The data source to fetch measurements from a configured cloud provider and image.",
|
||||
|
||||
Attributes: map[string]schema.Attribute{
|
||||
"csp": schema.StringAttribute{
|
||||
Description: "CSP (Cloud Service Provider) to use. (e.g. `azure`)",
|
||||
MarkdownDescription: "CSP (Cloud Service Provider) to use. (e.g. `azure`)\n" +
|
||||
"See the [full list of CSPs](https://docs.edgeless.systems/constellation/overview/clouds) that Constellation supports.",
|
||||
Required: true,
|
||||
Validators: []validator.String{
|
||||
stringvalidator.OneOf("aws", "azure", "gcp"),
|
||||
},
|
||||
},
|
||||
"attestation_variant": schema.StringAttribute{
|
||||
Description: "Attestation variant the image should work with. (e.g. `azure-sev-snp`)",
|
||||
MarkdownDescription: "Attestation variant the image should work with. Can be one of:\n" +
|
||||
" * `aws-sev-snp`\n" +
|
||||
" * `aws-nitro-tpm`\n" +
|
||||
" * `azure-sev-snp`\n" +
|
||||
" * `gcp-sev-es`\n",
|
||||
Required: true,
|
||||
Validators: []validator.String{
|
||||
stringvalidator.OneOf("aws-sev-snp", "aws-nitro-tpm", "azure-sev-snp", "gcp-sev-es"),
|
||||
},
|
||||
},
|
||||
"image_version": schema.StringAttribute{
|
||||
MarkdownDescription: "The image version to use",
|
||||
Required: true,
|
||||
},
|
||||
"maa_url": schema.StringAttribute{
|
||||
MarkdownDescription: "For Azure only, the URL of the Microsoft Azure Attestation service",
|
||||
Optional: true,
|
||||
},
|
||||
"id": schema.StringAttribute{
|
||||
Computed: true,
|
||||
MarkdownDescription: "The ID of the data source",
|
||||
},
|
||||
"measurements": schema.MapNestedAttribute{
|
||||
Computed: true,
|
||||
NestedObject: schema.NestedAttributeObject{
|
||||
Attributes: map[string]schema.Attribute{
|
||||
"expected": schema.StringAttribute{
|
||||
Computed: true,
|
||||
},
|
||||
"warn_only": schema.BoolAttribute{
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"attestation": schema.SingleNestedAttribute{
|
||||
Computed: true,
|
||||
MarkdownDescription: "Only relevant for SEV-SNP.",
|
||||
Description: "The values provide sensible defaults. See the docs for advanced usage.", // TODO(elchead): AB#3568
|
||||
Attributes: map[string]schema.Attribute{
|
||||
"bootloader_version": schema.Int64Attribute{
|
||||
Computed: true,
|
||||
},
|
||||
"tee_version": schema.Int64Attribute{
|
||||
Computed: true,
|
||||
},
|
||||
"snp_version": schema.Int64Attribute{
|
||||
Computed: true,
|
||||
},
|
||||
"microcode_version": schema.Int64Attribute{
|
||||
Computed: true,
|
||||
},
|
||||
"azure_firmware_signer_config": schema.SingleNestedAttribute{
|
||||
Computed: true,
|
||||
Attributes: map[string]schema.Attribute{
|
||||
"accepted_key_digests": schema.ListAttribute{
|
||||
Computed: true,
|
||||
ElementType: types.StringType,
|
||||
},
|
||||
"enforcement_policy": schema.StringAttribute{
|
||||
Computed: true,
|
||||
},
|
||||
"maa_url": schema.StringAttribute{
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
"amd_root_key": schema.StringAttribute{
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Read reads from the data source.
|
||||
func (d *AttestationDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
|
||||
var data AttestationDataSourceModel
|
||||
|
||||
// Read Terraform configuration data into the model
|
||||
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
|
||||
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
|
||||
csp := cloudprovider.FromString(data.CSP.ValueString())
|
||||
if csp == cloudprovider.Unknown {
|
||||
resp.Diagnostics.AddAttributeError(
|
||||
path.Root("csp"),
|
||||
"Invalid CSP",
|
||||
fmt.Sprintf("Invalid CSP: %s", data.CSP.ValueString()),
|
||||
)
|
||||
return
|
||||
}
|
||||
attestationVariant, err := variant.FromString(data.AttestationVariant.ValueString())
|
||||
if err != nil {
|
||||
resp.Diagnostics.AddAttributeError(
|
||||
path.Root("attestation_variant"),
|
||||
"Invalid Attestation Variant",
|
||||
fmt.Sprintf("Invalid attestation variant: %s", data.CSP.ValueString()),
|
||||
)
|
||||
return
|
||||
}
|
||||
if attestationVariant.Equal(variant.AzureSEVSNP{}) || attestationVariant.Equal(variant.AWSSEVSNP{}) {
|
||||
snpVersions, err := d.fetcher.FetchSEVSNPVersionLatest(ctx, attestationVariant)
|
||||
if err != nil {
|
||||
resp.Diagnostics.AddError("Fetching SNP Version numbers", err.Error())
|
||||
return
|
||||
}
|
||||
tfSnpAttestation, err := convertSNPAttestationTfStateCompatible(attestationVariant, snpVersions)
|
||||
if err != nil {
|
||||
resp.Diagnostics.AddError("Converting SNP attestation", err.Error())
|
||||
}
|
||||
diags := resp.State.SetAttribute(ctx, path.Root("attestation"), tfSnpAttestation)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
verifyFetcher := measurements.NewVerifyFetcher(sigstore.NewCosignVerifier, d.rekor, d.client)
|
||||
fetchedMeasurements, err := verifyFetcher.FetchAndVerifyMeasurements(ctx, data.ImageVersion.ValueString(),
|
||||
csp, attestationVariant, false)
|
||||
if err != nil {
|
||||
var rekErr *measurements.RekorError
|
||||
if errors.As(err, &rekErr) {
|
||||
resp.Diagnostics.AddWarning("Ignoring Rekor related error", err.Error())
|
||||
} else {
|
||||
resp.Diagnostics.AddError("fetching and verifying measurements", err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
tfMeasurements := convertMeasurementsTfStateCompatible(fetchedMeasurements)
|
||||
diags := resp.State.SetAttribute(ctx, path.Root("measurements"), tfMeasurements)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
tflog.Trace(ctx, "read constellation attestation data source")
|
||||
}
|
||||
|
||||
func convertSNPAttestationTfStateCompatible(attestationVariant variant.Variant,
|
||||
snpVersions attestationconfigapi.SEVSNPVersionAPI,
|
||||
) (tfSnpAttestation sevSnpAttestation, err error) {
|
||||
var cert config.Certificate
|
||||
switch attestationVariant.(type) {
|
||||
case variant.AWSSEVSNP:
|
||||
cert = config.DefaultForAWSSEVSNP().AMDRootKey
|
||||
case variant.AzureSEVSNP:
|
||||
cert = config.DefaultForAzureSEVSNP().AMDRootKey
|
||||
}
|
||||
certBytes, err := cert.MarshalJSON()
|
||||
if err != nil {
|
||||
return tfSnpAttestation, err
|
||||
}
|
||||
tfSnpAttestation = sevSnpAttestation{
|
||||
BootloaderVersion: snpVersions.Bootloader,
|
||||
TEEVersion: snpVersions.TEE,
|
||||
SNPVersion: snpVersions.SNP,
|
||||
MicrocodeVersion: snpVersions.Microcode,
|
||||
AMDRootKey: string(certBytes),
|
||||
}
|
||||
if attestationVariant.Equal(variant.AzureSEVSNP{}) {
|
||||
firmwareCfg := config.DefaultForAzureSEVSNP().FirmwareSignerConfig
|
||||
keyDigestAny, err := firmwareCfg.AcceptedKeyDigests.MarshalYAML()
|
||||
if err != nil {
|
||||
return tfSnpAttestation, err
|
||||
}
|
||||
keyDigest, ok := keyDigestAny.([]string)
|
||||
if !ok {
|
||||
return tfSnpAttestation, errors.New("reading Accepted Key Digests: could not convert to []string")
|
||||
}
|
||||
tfSnpAttestation.AzureSNPFirmwareSignerConfig = azureSnpFirmwareSignerConfig{
|
||||
AcceptedKeyDigests: keyDigest,
|
||||
EnforcementPolicy: firmwareCfg.EnforcementPolicy.String(),
|
||||
MAAURL: firmwareCfg.MAAURL,
|
||||
}
|
||||
}
|
||||
return tfSnpAttestation, nil
|
||||
}
|
||||
|
||||
func convertMeasurementsTfStateCompatible(m measurements.M) map[string]measurement {
|
||||
tfMeasurements := map[string]measurement{}
|
||||
for key, value := range m {
|
||||
keyStr := strconv.FormatUint(uint64(key), 10)
|
||||
tfMeasurements[keyStr] = measurement{
|
||||
Expected: hex.EncodeToString(value.Expected[:]),
|
||||
WarnOnly: bool(value.ValidationOpt),
|
||||
}
|
||||
}
|
||||
return tfMeasurements
|
||||
}
|
||||
|
||||
type measurement struct {
|
||||
Expected string `tfsdk:"expected"`
|
||||
WarnOnly bool `tfsdk:"warn_only"`
|
||||
}
|
||||
|
||||
type sevSnpAttestation struct {
|
||||
BootloaderVersion uint8 `tfsdk:"bootloader_version"`
|
||||
TEEVersion uint8 `tfsdk:"tee_version"`
|
||||
SNPVersion uint8 `tfsdk:"snp_version"`
|
||||
MicrocodeVersion uint8 `tfsdk:"microcode_version"`
|
||||
AMDRootKey string `tfsdk:"amd_root_key"`
|
||||
AzureSNPFirmwareSignerConfig azureSnpFirmwareSignerConfig `tfsdk:"azure_firmware_signer_config"`
|
||||
}
|
||||
|
||||
type azureSnpFirmwareSignerConfig struct {
|
||||
AcceptedKeyDigests []string `tfsdk:"accepted_key_digests"`
|
||||
EnforcementPolicy string `tfsdk:"enforcement_policy"`
|
||||
MAAURL string `tfsdk:"maa_url"`
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
Copyright (c) Edgeless Systems GmbH
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package provider
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
|
||||
)
|
||||
|
||||
func TestAccAttestationSource(t *testing.T) {
|
||||
// Set the path to the Terraform binary for acceptance testing when running under Bazel.
|
||||
bazelPreCheck := func() { bazelSetTerraformBinaryPath(t) }
|
||||
|
||||
testCases := map[string]resource.TestCase{
|
||||
"aws sev-snp succcess": {
|
||||
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
|
||||
PreCheck: bazelPreCheck,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testingConfig + `
|
||||
data "constellation_attestation" "test" {
|
||||
csp = "aws"
|
||||
attestation_variant = "aws-sev-snp"
|
||||
image_version = "v2.13.0"
|
||||
}
|
||||
`,
|
||||
Check: resource.ComposeAggregateTestCheckFunc(
|
||||
resource.TestCheckResourceAttr("data.constellation_attestation.test", "attestation.bootloader_version", "3"),
|
||||
resource.TestCheckResourceAttr("data.constellation_attestation.test", "attestation.microcode_version", "209"),
|
||||
resource.TestCheckResourceAttr("data.constellation_attestation.test", "attestation.snp_version", "20"),
|
||||
resource.TestCheckResourceAttr("data.constellation_attestation.test", "attestation.tee_version", "0"),
|
||||
resource.TestCheckResourceAttr("data.constellation_attestation.test", "attestation.amd_root_key", "\"-----BEGIN CERTIFICATE-----\\nMIIGYzCCBBKgAwIBAgIDAQAAMEYGCSqGSIb3DQEBCjA5oA8wDQYJYIZIAWUDBAIC\\nBQChHDAaBgkqhkiG9w0BAQgwDQYJYIZIAWUDBAICBQCiAwIBMKMDAgEBMHsxFDAS\\nBgNVBAsMC0VuZ2luZWVyaW5nMQswCQYDVQQGEwJVUzEUMBIGA1UEBwwLU2FudGEg\\nQ2xhcmExCzAJBgNVBAgMAkNBMR8wHQYDVQQKDBZBZHZhbmNlZCBNaWNybyBEZXZp\\nY2VzMRIwEAYDVQQDDAlBUkstTWlsYW4wHhcNMjAxMDIyMTcyMzA1WhcNNDUxMDIy\\nMTcyMzA1WjB7MRQwEgYDVQQLDAtFbmdpbmVlcmluZzELMAkGA1UEBhMCVVMxFDAS\\nBgNVBAcMC1NhbnRhIENsYXJhMQswCQYDVQQIDAJDQTEfMB0GA1UECgwWQWR2YW5j\\nZWQgTWljcm8gRGV2aWNlczESMBAGA1UEAwwJQVJLLU1pbGFuMIICIjANBgkqhkiG\\n9w0BAQEFAAOCAg8AMIICCgKCAgEA0Ld52RJOdeiJlqK2JdsVmD7FktuotWwX1fNg\\nW41XY9Xz1HEhSUmhLz9Cu9DHRlvgJSNxbeYYsnJfvyjx1MfU0V5tkKiU1EesNFta\\n1kTA0szNisdYc9isqk7mXT5+KfGRbfc4V/9zRIcE8jlHN61S1ju8X93+6dxDUrG2\\nSzxqJ4BhqyYmUDruPXJSX4vUc01P7j98MpqOS95rORdGHeI52Naz5m2B+O+vjsC0\\n60d37jY9LFeuOP4Meri8qgfi2S5kKqg/aF6aPtuAZQVR7u3KFYXP59XmJgtcog05\\ngmI0T/OitLhuzVvpZcLph0odh/1IPXqx3+MnjD97A7fXpqGd/y8KxX7jksTEzAOg\\nbKAeam3lm+3yKIcTYMlsRMXPcjNbIvmsBykD//xSniusuHBkgnlENEWx1UcbQQrs\\n+gVDkuVPhsnzIRNgYvM48Y+7LGiJYnrmE8xcrexekBxrva2V9TJQqnN3Q53kt5vi\\nQi3+gCfmkwC0F0tirIZbLkXPrPwzZ0M9eNxhIySb2npJfgnqz55I0u33wh4r0ZNQ\\neTGfw03MBUtyuzGesGkcw+loqMaq1qR4tjGbPYxCvpCq7+OgpCCoMNit2uLo9M18\\nfHz10lOMT8nWAUvRZFzteXCm+7PHdYPlmQwUw3LvenJ/ILXoQPHfbkH0CyPfhl1j\\nWhJFZasCAwEAAaN+MHwwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSFrBrRQ/fI\\nrFXUxR1BSKvVeErUUzAPBgNVHRMBAf8EBTADAQH/MDoGA1UdHwQzMDEwL6AtoCuG\\nKWh0dHBzOi8va2RzaW50Zi5hbWQuY29tL3ZjZWsvdjEvTWlsYW4vY3JsMEYGCSqG\\nSIb3DQEBCjA5oA8wDQYJYIZIAWUDBAICBQChHDAaBgkqhkiG9w0BAQgwDQYJYIZI\\nAWUDBAICBQCiAwIBMKMDAgEBA4ICAQC6m0kDp6zv4Ojfgy+zleehsx6ol0ocgVel\\nETobpx+EuCsqVFRPK1jZ1sp/lyd9+0fQ0r66n7kagRk4Ca39g66WGTJMeJdqYriw\\nSTjjDCKVPSesWXYPVAyDhmP5n2v+BYipZWhpvqpaiO+EGK5IBP+578QeW/sSokrK\\ndHaLAxG2LhZxj9aF73fqC7OAJZ5aPonw4RE299FVarh1Tx2eT3wSgkDgutCTB1Yq\\nzT5DuwvAe+co2CIVIzMDamYuSFjPN0BCgojl7V+bTou7dMsqIu/TW/rPCX9/EUcp\\nKGKqPQ3P+N9r1hjEFY1plBg93t53OOo49GNI+V1zvXPLI6xIFVsh+mto2RtgEX/e\\npmMKTNN6psW88qg7c1hTWtN6MbRuQ0vm+O+/2tKBF2h8THb94OvvHHoFDpbCELlq\\nHnIYhxy0YKXGyaW1NjfULxrrmxVW4wcn5E8GddmvNa6yYm8scJagEi13mhGu4Jqh\\n3QU3sf8iUSUr09xQDwHtOQUVIqx4maBZPBtSMf+qUDtjXSSq8lfWcd8bLr9mdsUn\\nJZJ0+tuPMKmBnSH860llKk+VpVQsgqbzDIvOLvD6W1Umq25boxCYJ+TuBoa4s+HH\\nCViAvgT9kf/rBq1d+ivj6skkHxuzcxbk1xv6ZGxrteJxVH7KlX7YRdZ6eARKwLe4\\nAFZEAwoKCQ==\\n-----END CERTIFICATE-----\\n\""),
|
||||
|
||||
resource.TestCheckResourceAttr("data.constellation_attestation.test", "measurements.0.expected", "7b068c0c3ac29afe264134536b9be26f1d4ccd575b88d3c3ceabf36ac99c0278"),
|
||||
resource.TestCheckResourceAttr("data.constellation_attestation.test", "measurements.0.warn_only", "true"),
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
"azure sev-snp success": {
|
||||
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
|
||||
PreCheck: bazelPreCheck,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testingConfig + `
|
||||
data "constellation_attestation" "test" {
|
||||
csp = "azure"
|
||||
attestation_variant = "azure-sev-snp"
|
||||
image_version = "v2.13.0"
|
||||
}
|
||||
`,
|
||||
Check: resource.ComposeAggregateTestCheckFunc(
|
||||
resource.TestCheckResourceAttr("data.constellation_attestation.test", "attestation.bootloader_version", "3"),
|
||||
resource.TestCheckResourceAttr("data.constellation_attestation.test", "attestation.microcode_version", "115"),
|
||||
resource.TestCheckResourceAttr("data.constellation_attestation.test", "attestation.snp_version", "8"),
|
||||
resource.TestCheckResourceAttr("data.constellation_attestation.test", "attestation.tee_version", "0"),
|
||||
|
||||
resource.TestCheckResourceAttr("data.constellation_attestation.test", "attestation.azure_firmware_signer_config.accepted_key_digests.0", "0356215882a825279a85b300b0b742931d113bf7e32dde2e50ffde7ec743ca491ecdd7f336dc28a6e0b2bb57af7a44a3"),
|
||||
resource.TestCheckResourceAttr("data.constellation_attestation.test", "attestation.azure_firmware_signer_config.enforcement_policy", "MAAFallback"),
|
||||
|
||||
resource.TestCheckResourceAttr("data.constellation_attestation.test", "attestation.amd_root_key", "\"-----BEGIN CERTIFICATE-----\\nMIIGYzCCBBKgAwIBAgIDAQAAMEYGCSqGSIb3DQEBCjA5oA8wDQYJYIZIAWUDBAIC\\nBQChHDAaBgkqhkiG9w0BAQgwDQYJYIZIAWUDBAICBQCiAwIBMKMDAgEBMHsxFDAS\\nBgNVBAsMC0VuZ2luZWVyaW5nMQswCQYDVQQGEwJVUzEUMBIGA1UEBwwLU2FudGEg\\nQ2xhcmExCzAJBgNVBAgMAkNBMR8wHQYDVQQKDBZBZHZhbmNlZCBNaWNybyBEZXZp\\nY2VzMRIwEAYDVQQDDAlBUkstTWlsYW4wHhcNMjAxMDIyMTcyMzA1WhcNNDUxMDIy\\nMTcyMzA1WjB7MRQwEgYDVQQLDAtFbmdpbmVlcmluZzELMAkGA1UEBhMCVVMxFDAS\\nBgNVBAcMC1NhbnRhIENsYXJhMQswCQYDVQQIDAJDQTEfMB0GA1UECgwWQWR2YW5j\\nZWQgTWljcm8gRGV2aWNlczESMBAGA1UEAwwJQVJLLU1pbGFuMIICIjANBgkqhkiG\\n9w0BAQEFAAOCAg8AMIICCgKCAgEA0Ld52RJOdeiJlqK2JdsVmD7FktuotWwX1fNg\\nW41XY9Xz1HEhSUmhLz9Cu9DHRlvgJSNxbeYYsnJfvyjx1MfU0V5tkKiU1EesNFta\\n1kTA0szNisdYc9isqk7mXT5+KfGRbfc4V/9zRIcE8jlHN61S1ju8X93+6dxDUrG2\\nSzxqJ4BhqyYmUDruPXJSX4vUc01P7j98MpqOS95rORdGHeI52Naz5m2B+O+vjsC0\\n60d37jY9LFeuOP4Meri8qgfi2S5kKqg/aF6aPtuAZQVR7u3KFYXP59XmJgtcog05\\ngmI0T/OitLhuzVvpZcLph0odh/1IPXqx3+MnjD97A7fXpqGd/y8KxX7jksTEzAOg\\nbKAeam3lm+3yKIcTYMlsRMXPcjNbIvmsBykD//xSniusuHBkgnlENEWx1UcbQQrs\\n+gVDkuVPhsnzIRNgYvM48Y+7LGiJYnrmE8xcrexekBxrva2V9TJQqnN3Q53kt5vi\\nQi3+gCfmkwC0F0tirIZbLkXPrPwzZ0M9eNxhIySb2npJfgnqz55I0u33wh4r0ZNQ\\neTGfw03MBUtyuzGesGkcw+loqMaq1qR4tjGbPYxCvpCq7+OgpCCoMNit2uLo9M18\\nfHz10lOMT8nWAUvRZFzteXCm+7PHdYPlmQwUw3LvenJ/ILXoQPHfbkH0CyPfhl1j\\nWhJFZasCAwEAAaN+MHwwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSFrBrRQ/fI\\nrFXUxR1BSKvVeErUUzAPBgNVHRMBAf8EBTADAQH/MDoGA1UdHwQzMDEwL6AtoCuG\\nKWh0dHBzOi8va2RzaW50Zi5hbWQuY29tL3ZjZWsvdjEvTWlsYW4vY3JsMEYGCSqG\\nSIb3DQEBCjA5oA8wDQYJYIZIAWUDBAICBQChHDAaBgkqhkiG9w0BAQgwDQYJYIZI\\nAWUDBAICBQCiAwIBMKMDAgEBA4ICAQC6m0kDp6zv4Ojfgy+zleehsx6ol0ocgVel\\nETobpx+EuCsqVFRPK1jZ1sp/lyd9+0fQ0r66n7kagRk4Ca39g66WGTJMeJdqYriw\\nSTjjDCKVPSesWXYPVAyDhmP5n2v+BYipZWhpvqpaiO+EGK5IBP+578QeW/sSokrK\\ndHaLAxG2LhZxj9aF73fqC7OAJZ5aPonw4RE299FVarh1Tx2eT3wSgkDgutCTB1Yq\\nzT5DuwvAe+co2CIVIzMDamYuSFjPN0BCgojl7V+bTou7dMsqIu/TW/rPCX9/EUcp\\nKGKqPQ3P+N9r1hjEFY1plBg93t53OOo49GNI+V1zvXPLI6xIFVsh+mto2RtgEX/e\\npmMKTNN6psW88qg7c1hTWtN6MbRuQ0vm+O+/2tKBF2h8THb94OvvHHoFDpbCELlq\\nHnIYhxy0YKXGyaW1NjfULxrrmxVW4wcn5E8GddmvNa6yYm8scJagEi13mhGu4Jqh\\n3QU3sf8iUSUr09xQDwHtOQUVIqx4maBZPBtSMf+qUDtjXSSq8lfWcd8bLr9mdsUn\\nJZJ0+tuPMKmBnSH860llKk+VpVQsgqbzDIvOLvD6W1Umq25boxCYJ+TuBoa4s+HH\\nCViAvgT9kf/rBq1d+ivj6skkHxuzcxbk1xv6ZGxrteJxVH7KlX7YRdZ6eARKwLe4\\nAFZEAwoKCQ==\\n-----END CERTIFICATE-----\\n\""),
|
||||
|
||||
resource.TestCheckResourceAttr("data.constellation_attestation.test", "measurements.1.expected", "3d458cfe55cc03ea1f443f1562beec8df51c75e14a9fcf9a7234a13f198e7969"),
|
||||
resource.TestCheckResourceAttr("data.constellation_attestation.test", "measurements.1.warn_only", "true"),
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
"gcp sev-snp succcess": {
|
||||
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
|
||||
PreCheck: bazelPreCheck,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testingConfig + `
|
||||
data "constellation_attestation" "test" {
|
||||
csp = "gcp"
|
||||
attestation_variant = "gcp-sev-es"
|
||||
image_version = "v2.13.0"
|
||||
}
|
||||
`,
|
||||
Check: resource.ComposeAggregateTestCheckFunc(
|
||||
resource.TestCheckResourceAttr("data.constellation_attestation.test", "measurements.1.expected", "745f2fb4235e4647aa0ad5ace781cd929eb68c28870e7dd5d1a1535854325e56"),
|
||||
resource.TestCheckResourceAttr("data.constellation_attestation.test", "measurements.1.warn_only", "true"),
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
resource.Test(t, tc)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -160,8 +160,6 @@ func (d *ImageDataSource) Read(ctx context.Context, req datasource.ReadRequest,
|
|||
|
||||
// Save data into Terraform state
|
||||
data.Reference = types.StringValue(imageRef)
|
||||
// Use a placeholder ID for testing, as per https://developer.hashicorp.com/terraform/plugin/framework/acctests#no-id-found-in-attributes
|
||||
data.ID = types.StringValue("placeholder")
|
||||
|
||||
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
|
||||
}
|
||||
|
|
|
@ -85,6 +85,6 @@ func (p *ConstellationProvider) Resources(_ context.Context) []func() resource.R
|
|||
// DataSources lists the data sources implemented by the provider.
|
||||
func (p *ConstellationProvider) DataSources(_ context.Context) []func() datasource.DataSource {
|
||||
return []func() datasource.DataSource{
|
||||
NewImageDataSource,
|
||||
NewImageDataSource, NewAttestationDataSource,
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue