blob: b161b88e670a2e1bdfbf76f42b3632f9b57d616c [file] [log] [blame]
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package containeranalysis_test
import (
"encoding/base64"
"fmt"
"io/ioutil"
"testing"
"github.com/hashicorp/terraform-provider-google-beta/google-beta/acctest"
"github.com/hashicorp/terraform-provider-google-beta/google-beta/tpgresource"
transport_tpg "github.com/hashicorp/terraform-provider-google-beta/google-beta/transport"
"crypto/sha512"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"google.golang.org/api/cloudkms/v1"
)
const testAttestationOccurrenceImageUrl = "gcr.io/cloud-marketplace/google/ubuntu1804"
const testAttestationOccurrenceImageDigest = "sha256:3593cd4ac7d782d460dc86ba9870a3beaf81c8f5cdbcc8880bf9a5ef6af10c5a"
const testAttestationOccurrencePayloadTemplate = "test-fixtures/generated_payload.json.tmpl"
var testAttestationOccurrenceFullImagePath = fmt.Sprintf("%s@%s", testAttestationOccurrenceImageUrl, testAttestationOccurrenceImageDigest)
func getTestOccurrenceAttestationPayload(t *testing.T) string {
payloadTmpl, err := ioutil.ReadFile(testAttestationOccurrencePayloadTemplate)
if err != nil {
t.Fatal(err.Error())
}
return fmt.Sprintf(string(payloadTmpl),
testAttestationOccurrenceImageUrl,
testAttestationOccurrenceImageDigest)
}
func getSignedTestOccurrenceAttestationPayload(
t *testing.T, config *transport_tpg.Config,
signingKey acctest.BootstrappedKMS, rawPayload string) string {
pbytes := []byte(rawPayload)
ssum := sha512.Sum512(pbytes)
hashed := base64.StdEncoding.EncodeToString(ssum[:])
signed, err := config.NewKmsClient(config.UserAgent).Projects.Locations.KeyRings.CryptoKeys.
CryptoKeyVersions.AsymmetricSign(
fmt.Sprintf("%s/cryptoKeyVersions/1", signingKey.CryptoKey.Name),
&cloudkms.AsymmetricSignRequest{
Digest: &cloudkms.Digest{
Sha512: hashed,
},
}).Do()
if err != nil {
t.Fatalf("Unable to sign attestation payload with KMS key: %s", err)
}
return signed.Signature
}
func TestAccContainerAnalysisOccurrence_basic(t *testing.T) {
t.Parallel()
randSuffix := acctest.RandString(t, 10)
config := acctest.BootstrapConfig(t)
if config == nil {
return
}
signKey := acctest.BootstrapKMSKeyWithPurpose(t, "ASYMMETRIC_SIGN")
payload := getTestOccurrenceAttestationPayload(t)
signed := getSignedTestOccurrenceAttestationPayload(t, config, signKey, payload)
params := map[string]interface{}{
"random_suffix": randSuffix,
"image_url": testAttestationOccurrenceFullImagePath,
"key_ring": tpgresource.GetResourceNameFromSelfLink(signKey.KeyRing.Name),
"crypto_key": tpgresource.GetResourceNameFromSelfLink(signKey.CryptoKey.Name),
"payload": base64.StdEncoding.EncodeToString([]byte(payload)),
"signature": base64.StdEncoding.EncodeToString([]byte(signed)),
}
acctest.VcrTest(t, resource.TestCase{
PreCheck: func() { acctest.AccTestPreCheck(t) },
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
CheckDestroy: testAccCheckContainerAnalysisNoteDestroyProducer(t),
Steps: []resource.TestStep{
{
Config: testAccContainerAnalysisOccurence_basic(params),
},
{
ResourceName: "google_container_analysis_occurrence.occurrence",
ImportState: true,
ImportStateVerify: true,
},
},
})
}
func TestAccContainerAnalysisOccurrence_multipleSignatures(t *testing.T) {
t.Parallel()
randSuffix := acctest.RandString(t, 10)
config := acctest.BootstrapConfig(t)
if config == nil {
return
}
payload := getTestOccurrenceAttestationPayload(t)
key1 := acctest.BootstrapKMSKeyWithPurposeInLocationAndName(t, "ASYMMETRIC_SIGN", "global", "tf-bootstrap-binauthz-key1")
signature1 := getSignedTestOccurrenceAttestationPayload(t, config, key1, payload)
key2 := acctest.BootstrapKMSKeyWithPurposeInLocationAndName(t, "ASYMMETRIC_SIGN", "global", "tf-bootstrap-binauthz-key2")
signature2 := getSignedTestOccurrenceAttestationPayload(t, config, key2, payload)
paramsMultipleSignatures := map[string]interface{}{
"random_suffix": randSuffix,
"image_url": testAttestationOccurrenceFullImagePath,
"key_ring": tpgresource.GetResourceNameFromSelfLink(key1.KeyRing.Name),
"payload": base64.StdEncoding.EncodeToString([]byte(payload)),
"key1": tpgresource.GetResourceNameFromSelfLink(key1.CryptoKey.Name),
"signature1": base64.StdEncoding.EncodeToString([]byte(signature1)),
"key2": tpgresource.GetResourceNameFromSelfLink(key2.CryptoKey.Name),
"signature2": base64.StdEncoding.EncodeToString([]byte(signature2)),
}
paramsSingle := map[string]interface{}{
"random_suffix": randSuffix,
"image_url": testAttestationOccurrenceFullImagePath,
"key_ring": tpgresource.GetResourceNameFromSelfLink(key1.KeyRing.Name),
"crypto_key": tpgresource.GetResourceNameFromSelfLink(key1.CryptoKey.Name),
"payload": base64.StdEncoding.EncodeToString([]byte(payload)),
"signature": base64.StdEncoding.EncodeToString([]byte(signature1)),
}
acctest.VcrTest(t, resource.TestCase{
PreCheck: func() { acctest.AccTestPreCheck(t) },
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
CheckDestroy: testAccCheckContainerAnalysisNoteDestroyProducer(t),
Steps: []resource.TestStep{
{
Config: testAccContainerAnalysisOccurence_multipleSignatures(paramsMultipleSignatures),
},
{
ResourceName: "google_container_analysis_occurrence.occurrence",
ImportState: true,
ImportStateVerify: true,
},
{
Config: testAccContainerAnalysisOccurence_basic(paramsSingle),
},
{
ResourceName: "google_container_analysis_occurrence.occurrence",
ImportState: true,
ImportStateVerify: true,
},
},
})
}
func testAccContainerAnalysisOccurence_basic(params map[string]interface{}) string {
return acctest.Nprintf(`
resource "google_binary_authorization_attestor" "attestor" {
name = "test-attestor%{random_suffix}"
attestation_authority_note {
note_reference = google_container_analysis_note.note.name
public_keys {
id = data.google_kms_crypto_key_version.version.id
pkix_public_key {
public_key_pem = data.google_kms_crypto_key_version.version.public_key[0].pem
signature_algorithm = data.google_kms_crypto_key_version.version.public_key[0].algorithm
}
}
}
}
resource "google_container_analysis_note" "note" {
name = "test-attestor-note%{random_suffix}"
attestation_authority {
hint {
human_readable_name = "Attestor Note"
}
}
}
data "google_kms_key_ring" "keyring" {
name = "%{key_ring}"
location = "global"
}
data "google_kms_crypto_key" "crypto-key" {
name = "%{crypto_key}"
key_ring = data.google_kms_key_ring.keyring.id
}
data "google_kms_crypto_key_version" "version" {
crypto_key = data.google_kms_crypto_key.crypto-key.id
}
resource "google_container_analysis_occurrence" "occurrence" {
resource_uri = "%{image_url}"
note_name = google_container_analysis_note.note.id
attestation {
serialized_payload = "%{payload}"
signatures {
public_key_id = data.google_kms_crypto_key_version.version.id
signature = "%{signature}"
}
}
}
`, params)
}
func testAccContainerAnalysisOccurence_multipleSignatures(params map[string]interface{}) string {
return acctest.Nprintf(`
resource "google_binary_authorization_attestor" "attestor" {
name = "test-attestor%{random_suffix}"
attestation_authority_note {
note_reference = google_container_analysis_note.note.name
public_keys {
id = data.google_kms_crypto_key_version.version-key1.id
pkix_public_key {
public_key_pem = data.google_kms_crypto_key_version.version-key1.public_key[0].pem
signature_algorithm = data.google_kms_crypto_key_version.version-key1.public_key[0].algorithm
}
}
public_keys {
id = data.google_kms_crypto_key_version.version-key2.id
pkix_public_key {
public_key_pem = data.google_kms_crypto_key_version.version-key2.public_key[0].pem
signature_algorithm = data.google_kms_crypto_key_version.version-key2.public_key[0].algorithm
}
}
}
}
resource "google_container_analysis_note" "note" {
name = "test-attestor-note%{random_suffix}"
attestation_authority {
hint {
human_readable_name = "Attestor Note"
}
}
}
data "google_kms_key_ring" "keyring" {
name = "%{key_ring}"
location = "global"
}
data "google_kms_crypto_key" "crypto-key1" {
name = "%{key1}"
key_ring = data.google_kms_key_ring.keyring.id
}
data "google_kms_crypto_key" "crypto-key2" {
name = "%{key2}"
key_ring = data.google_kms_key_ring.keyring.id
}
data "google_kms_crypto_key_version" "version-key1" {
crypto_key = data.google_kms_crypto_key.crypto-key1.id
}
data "google_kms_crypto_key_version" "version-key2" {
crypto_key = data.google_kms_crypto_key.crypto-key2.id
}
resource "google_container_analysis_occurrence" "occurrence" {
resource_uri = "%{image_url}"
note_name = google_container_analysis_note.note.id
attestation {
serialized_payload = "%{payload}"
signatures {
public_key_id = data.google_kms_crypto_key_version.version-key1.id
signature = "%{signature1}"
}
signatures {
public_key_id = data.google_kms_crypto_key_version.version-key2.id
signature = "%{signature2}"
}
}
}
`, params)
}