Skip to content

Commit 48a1318

Browse files
drebesmodular-magician
authored andcommitted
binary_authorization_attestor KMS support
Signed-off-by: Modular Magician <[email protected]>
1 parent cb7b92a commit 48a1318

7 files changed

+428
-16
lines changed

google/bootstrap_utils_test.go

+32-9
Original file line numberDiff line numberDiff line change
@@ -11,30 +11,43 @@ import (
1111
)
1212

1313
var SharedKeyRing = "tftest-shared-keyring-1"
14-
var SharedCyptoKey = "tftest-shared-key-1"
14+
var SharedCryptoKey = map[string]string{
15+
"ENCRYPT_DECRYPT": "tftest-shared-key-1",
16+
"ASYMMETRIC_SIGN": "tftest-shared-sign-key-1",
17+
"ASYMMETRIC_DECRYPT": "tftest-shared-decrypt-key-1",
18+
}
1519

1620
type bootstrappedKMS struct {
1721
*cloudkms.KeyRing
1822
*cloudkms.CryptoKey
1923
}
2024

21-
// BootstrapKMSKey returns a KMS key in the "global" location.
22-
// See BootstrapKMSKeyInLocation.
2325
func BootstrapKMSKey(t *testing.T) bootstrappedKMS {
2426
return BootstrapKMSKeyInLocation(t, "global")
2527
}
2628

29+
func BootstrapKMSKeyInLocation(t *testing.T, locationID string) bootstrappedKMS {
30+
return BootstrapKMSKeyWithPurposeInLocation(t, "ENCRYPT_DECRYPT", locationID)
31+
}
32+
33+
// BootstrapKMSKeyWithPurpose returns a KMS key in the "global" location.
34+
// See BootstrapKMSKeyWithPurposeInLocation.
35+
func BootstrapKMSKeyWithPurpose(t *testing.T, purpose string) bootstrappedKMS {
36+
return BootstrapKMSKeyWithPurposeInLocation(t, purpose, "global")
37+
}
38+
2739
/**
28-
* BootstrapKMSKeyWithLocation will return a KMS key in a particular location
29-
* that can be used in tests that are testing KMS integration with other resources.
40+
* BootstrapKMSKeyWithPurposeInLocation will return a KMS key in a
41+
* particular location with the given purpose that can be used
42+
* in tests that are testing KMS integration with other resources.
3043
*
3144
* This will either return an existing key or create one if it hasn't been created
3245
* in the project yet. The motivation is because keyrings don't get deleted and we
3346
* don't want a linear growth of disabled keyrings in a project. We also don't want
3447
* to incur the overhead of creating a new project for each test that needs to use
3548
* a KMS key.
3649
**/
37-
func BootstrapKMSKeyInLocation(t *testing.T, locationID string) bootstrappedKMS {
50+
func BootstrapKMSKeyWithPurposeInLocation(t *testing.T, purpose, locationID string) bootstrappedKMS {
3851
if v := os.Getenv("TF_ACC"); v == "" {
3952
log.Println("Acceptance tests and bootstrapping skipped unless env 'TF_ACC' set")
4053

@@ -49,7 +62,7 @@ func BootstrapKMSKeyInLocation(t *testing.T, locationID string) bootstrappedKMS
4962
keyRingParent := fmt.Sprintf("projects/%s/locations/%s", projectID, locationID)
5063
keyRingName := fmt.Sprintf("%s/keyRings/%s", keyRingParent, SharedKeyRing)
5164
keyParent := fmt.Sprintf("projects/%s/locations/%s/keyRings/%s", projectID, locationID, SharedKeyRing)
52-
keyName := fmt.Sprintf("%s/cryptoKeys/%s", keyParent, SharedCyptoKey)
65+
keyName := fmt.Sprintf("%s/cryptoKeys/%s", keyParent, SharedCryptoKey[purpose])
5366

5467
config := &Config{
5568
Credentials: getTestCredsFromEnv(),
@@ -87,12 +100,22 @@ func BootstrapKMSKeyInLocation(t *testing.T, locationID string) bootstrappedKMS
87100
cryptoKey, err := kmsClient.Projects.Locations.KeyRings.CryptoKeys.Get(keyName).Do()
88101
if err != nil {
89102
if isGoogleApiErrorWithCode(err, 404) {
103+
algos := map[string]string{
104+
"ENCRYPT_DECRYPT": "GOOGLE_SYMMETRIC_ENCRYPTION",
105+
"ASYMMETRIC_SIGN": "RSA_SIGN_PKCS1_4096_SHA512",
106+
"ASYMMETRIC_DECRYPT": "RSA_DECRYPT_OAEP_4096_SHA512",
107+
}
108+
template := cloudkms.CryptoKeyVersionTemplate{
109+
Algorithm: algos[purpose],
110+
}
111+
90112
newKey := cloudkms.CryptoKey{
91-
Purpose: "ENCRYPT_DECRYPT",
113+
Purpose: purpose,
114+
VersionTemplate: &template,
92115
}
93116

94117
cryptoKey, err = kmsClient.Projects.Locations.KeyRings.CryptoKeys.Create(keyParent, &newKey).
95-
CryptoKeyId(SharedCyptoKey).Do()
118+
CryptoKeyId(SharedCryptoKey[purpose]).Do()
96119
if err != nil {
97120
t.Errorf("Unable to bootstrap KMS key. Cannot create new CryptoKey: %s", err)
98121
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
package google
2+
3+
import (
4+
"fmt"
5+
"log"
6+
"strconv"
7+
"strings"
8+
9+
"github.com/hashicorp/terraform/helper/schema"
10+
)
11+
12+
func dataSourceGoogleKmsCryptoKeyVersion() *schema.Resource {
13+
return &schema.Resource{
14+
Read: dataSourceGoogleKmsCryptoKeyVersionRead,
15+
Schema: map[string]*schema.Schema{
16+
"crypto_key": {
17+
Type: schema.TypeString,
18+
Required: true,
19+
ForceNew: true,
20+
},
21+
"version": {
22+
Type: schema.TypeInt,
23+
Optional: true,
24+
Default: 1,
25+
},
26+
"algorithm": {
27+
Type: schema.TypeString,
28+
Computed: true,
29+
},
30+
"protection_level": {
31+
Type: schema.TypeString,
32+
Computed: true,
33+
},
34+
"state": {
35+
Type: schema.TypeString,
36+
Computed: true,
37+
},
38+
"public_key": {
39+
Type: schema.TypeList,
40+
Optional: true,
41+
MaxItems: 1,
42+
Elem: &schema.Resource{
43+
Schema: map[string]*schema.Schema{
44+
"algorithm": {
45+
Type: schema.TypeString,
46+
Computed: true,
47+
},
48+
"pem": {
49+
Type: schema.TypeString,
50+
Computed: true,
51+
},
52+
},
53+
},
54+
},
55+
},
56+
}
57+
}
58+
59+
func dataSourceGoogleKmsCryptoKeyVersionRead(d *schema.ResourceData, meta interface{}) error {
60+
config := meta.(*Config)
61+
62+
url, err := replaceVars(d, config, "{{KmsBasePath}}{{crypto_key}}/cryptoKeyVersions/{{version}}")
63+
if err != nil {
64+
return err
65+
}
66+
67+
log.Printf("[DEBUG] Getting attributes for CryptoKeyVersion: %#v", url)
68+
res, err := sendRequest(config, "GET", url, nil)
69+
if err != nil {
70+
return handleNotFoundError(err, d, fmt.Sprintf("KmsCryptoKeyVersion %q", d.Id()))
71+
}
72+
73+
if err := d.Set("version", flattenKmsCryptoKeyVersionVersion(res["name"], d)); err != nil {
74+
return fmt.Errorf("Error reading CryptoKeyVersion: %s", err)
75+
}
76+
if err := d.Set("state", flattenKmsCryptoKeyVersionState(res["state"], d)); err != nil {
77+
return fmt.Errorf("Error reading CryptoKeyVersion: %s", err)
78+
}
79+
if err := d.Set("protection_level", flattenKmsCryptoKeyVersionProtectionLevel(res["protectionLevel"], d)); err != nil {
80+
return fmt.Errorf("Error reading CryptoKeyVersion: %s", err)
81+
}
82+
if err := d.Set("algorithm", flattenKmsCryptoKeyVersionAlgorithm(res["algorithm"], d)); err != nil {
83+
return fmt.Errorf("Error reading CryptoKeyVersion: %s", err)
84+
}
85+
86+
url, err = replaceVars(d, config, "{{KmsBasePath}}{{crypto_key}}")
87+
if err != nil {
88+
return err
89+
}
90+
91+
log.Printf("[DEBUG] Getting purpose of CryptoKey: %#v", url)
92+
res, err = sendRequest(config, "GET", url, nil)
93+
if err != nil {
94+
return handleNotFoundError(err, d, fmt.Sprintf("KmsCryptoKey %q", d.Id()))
95+
}
96+
97+
if res["purpose"] == "ASYMMETRIC_SIGN" || res["purpose"] == "ASYMMETRIC_DECRYPT" {
98+
url, err = replaceVars(d, config, "{{KmsBasePath}}{{crypto_key}}/cryptoKeyVersions/{{version}}/publicKey")
99+
if err != nil {
100+
return err
101+
}
102+
log.Printf("[DEBUG] Getting public key of CryptoKeyVersion: %#v", url)
103+
res, _ = sendRequest(config, "GET", url, nil)
104+
105+
if err := d.Set("public_key", flattenKmsCryptoKeyVersionPublicKey(res, d)); err != nil {
106+
return fmt.Errorf("Error reading CryptoKeyVersion public key: %s", err)
107+
}
108+
}
109+
d.SetId(fmt.Sprintf("//cloudkms.googleapis.com/%s/cryptoKeyVersions/%d", d.Get("crypto_key"), d.Get("version")))
110+
111+
return nil
112+
}
113+
114+
func flattenKmsCryptoKeyVersionVersion(v interface{}, d *schema.ResourceData) interface{} {
115+
parts := strings.Split(v.(string), "/")
116+
version := parts[len(parts)-1]
117+
// Handles the string fixed64 format
118+
if intVal, err := strconv.ParseInt(version, 10, 64); err == nil {
119+
return intVal
120+
} // let terraform core handle it if we can't convert the string to an int.
121+
return v
122+
}
123+
124+
func flattenKmsCryptoKeyVersionState(v interface{}, d *schema.ResourceData) interface{} {
125+
return v
126+
}
127+
128+
func flattenKmsCryptoKeyVersionProtectionLevel(v interface{}, d *schema.ResourceData) interface{} {
129+
return v
130+
}
131+
132+
func flattenKmsCryptoKeyVersionAlgorithm(v interface{}, d *schema.ResourceData) interface{} {
133+
return v
134+
}
135+
136+
func flattenKmsCryptoKeyVersionPublicKey(v interface{}, d *schema.ResourceData) interface{} {
137+
if v == nil {
138+
return nil
139+
}
140+
original := v.(map[string]interface{})
141+
if len(original) == 0 {
142+
return nil
143+
}
144+
transformed := make(map[string]interface{})
145+
transformed["pem"] =
146+
flattenKmsCryptoKeyVersionPublicKeyPem(original["pem"], d)
147+
transformed["algorithm"] =
148+
flattenKmsCryptoKeyVersionPublicKeyAlgorithm(original["algorithm"], d)
149+
return []interface{}{transformed}
150+
}
151+
func flattenKmsCryptoKeyVersionPublicKeyPem(v interface{}, d *schema.ResourceData) interface{} {
152+
return v
153+
}
154+
155+
func flattenKmsCryptoKeyVersionPublicKeyAlgorithm(v interface{}, d *schema.ResourceData) interface{} {
156+
return v
157+
}

google/provider.go

+1
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ func Provider() terraform.ResourceProvider {
178178
"google_kms_secret": dataSourceGoogleKmsSecret(),
179179
"google_kms_key_ring": dataSourceGoogleKmsKeyRing(),
180180
"google_kms_crypto_key": dataSourceGoogleKmsCryptoKey(),
181+
"google_kms_crypto_key_version": dataSourceGoogleKmsCryptoKeyVersion(),
181182
"google_folder": dataSourceGoogleFolder(),
182183
"google_folder_organization_policy": dataSourceGoogleFolderOrganizationPolicy(),
183184
"google_netblock_ip_ranges": dataSourceGoogleNetblockIpRanges(),

google/resource_binary_authorization_attestor.go

+84-2
Original file line numberDiff line numberDiff line change
@@ -61,15 +61,32 @@ func resourceBinaryAuthorizationAttestor() *schema.Resource {
6161
Schema: map[string]*schema.Schema{
6262
"ascii_armored_pgp_public_key": {
6363
Type: schema.TypeString,
64-
Required: true,
64+
Optional: true,
6565
},
6666
"comment": {
6767
Type: schema.TypeString,
6868
Optional: true,
6969
},
7070
"id": {
7171
Type: schema.TypeString,
72-
Computed: true,
72+
Optional: true,
73+
},
74+
"pkix_public_key": {
75+
Type: schema.TypeList,
76+
Optional: true,
77+
MaxItems: 1,
78+
Elem: &schema.Resource{
79+
Schema: map[string]*schema.Schema{
80+
"public_key_pem": {
81+
Type: schema.TypeString,
82+
Optional: true,
83+
},
84+
"signature_algorithm": {
85+
Type: schema.TypeString,
86+
Optional: true,
87+
},
88+
},
89+
},
7390
},
7491
},
7592
},
@@ -320,6 +337,7 @@ func flattenBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeys(v inte
320337
"comment": flattenBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeysComment(original["comment"], d),
321338
"id": flattenBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeysId(original["id"], d),
322339
"ascii_armored_pgp_public_key": flattenBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeysAsciiArmoredPgpPublicKey(original["asciiArmoredPgpPublicKey"], d),
340+
"pkix_public_key": flattenBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeysPkixPublicKey(original["pkixPublicKey"], d),
323341
})
324342
}
325343
return transformed
@@ -336,6 +354,29 @@ func flattenBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeysAsciiAr
336354
return v
337355
}
338356

357+
func flattenBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeysPkixPublicKey(v interface{}, d *schema.ResourceData) interface{} {
358+
if v == nil {
359+
return nil
360+
}
361+
original := v.(map[string]interface{})
362+
if len(original) == 0 {
363+
return nil
364+
}
365+
transformed := make(map[string]interface{})
366+
transformed["public_key_pem"] =
367+
flattenBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeysPkixPublicKeyPublicKeyPem(original["publicKeyPem"], d)
368+
transformed["signature_algorithm"] =
369+
flattenBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeysPkixPublicKeySignatureAlgorithm(original["signatureAlgorithm"], d)
370+
return []interface{}{transformed}
371+
}
372+
func flattenBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeysPkixPublicKeyPublicKeyPem(v interface{}, d *schema.ResourceData) interface{} {
373+
return v
374+
}
375+
376+
func flattenBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeysPkixPublicKeySignatureAlgorithm(v interface{}, d *schema.ResourceData) interface{} {
377+
return v
378+
}
379+
339380
func flattenBinaryAuthorizationAttestorAttestationAuthorityNoteDelegationServiceAccountEmail(v interface{}, d *schema.ResourceData) interface{} {
340381
return v
341382
}
@@ -426,6 +467,13 @@ func expandBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeys(v inter
426467
transformed["asciiArmoredPgpPublicKey"] = transformedAsciiArmoredPgpPublicKey
427468
}
428469

470+
transformedPkixPublicKey, err := expandBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeysPkixPublicKey(original["pkix_public_key"], d, config)
471+
if err != nil {
472+
return nil, err
473+
} else if val := reflect.ValueOf(transformedPkixPublicKey); val.IsValid() && !isEmptyValue(val) {
474+
transformed["pkixPublicKey"] = transformedPkixPublicKey
475+
}
476+
429477
req = append(req, transformed)
430478
}
431479
return req, nil
@@ -443,6 +491,40 @@ func expandBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeysAsciiArm
443491
return v, nil
444492
}
445493

494+
func expandBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeysPkixPublicKey(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
495+
l := v.([]interface{})
496+
if len(l) == 0 || l[0] == nil {
497+
return nil, nil
498+
}
499+
raw := l[0]
500+
original := raw.(map[string]interface{})
501+
transformed := make(map[string]interface{})
502+
503+
transformedPublicKeyPem, err := expandBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeysPkixPublicKeyPublicKeyPem(original["public_key_pem"], d, config)
504+
if err != nil {
505+
return nil, err
506+
} else if val := reflect.ValueOf(transformedPublicKeyPem); val.IsValid() && !isEmptyValue(val) {
507+
transformed["publicKeyPem"] = transformedPublicKeyPem
508+
}
509+
510+
transformedSignatureAlgorithm, err := expandBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeysPkixPublicKeySignatureAlgorithm(original["signature_algorithm"], d, config)
511+
if err != nil {
512+
return nil, err
513+
} else if val := reflect.ValueOf(transformedSignatureAlgorithm); val.IsValid() && !isEmptyValue(val) {
514+
transformed["signatureAlgorithm"] = transformedSignatureAlgorithm
515+
}
516+
517+
return transformed, nil
518+
}
519+
520+
func expandBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeysPkixPublicKeyPublicKeyPem(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
521+
return v, nil
522+
}
523+
524+
func expandBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeysPkixPublicKeySignatureAlgorithm(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
525+
return v, nil
526+
}
527+
446528
func expandBinaryAuthorizationAttestorAttestationAuthorityNoteDelegationServiceAccountEmail(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
447529
return v, nil
448530
}

0 commit comments

Comments
 (0)