Skip to content

Commit b60638c

Browse files
Add support for Customer Key Version and Encrypted Data Keys (#1203)
Co-authored-by: Jarrett Spiker <[email protected]>
1 parent 4dfed51 commit b60638c

11 files changed

+306
-0
lines changed

aws_oidc_configuration.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ import (
88

99
const OIDCConfigPathFormat = "oidc-configurations/%s"
1010

11+
// AWSOIDCConfigurations describes all the AWS OIDC configuration related methods that the HCP Terraform API supports.
12+
// HCP Terraform API docs:
13+
// https://developer.hashicorp.com/terraform/cloud-docs/api-docs/hold-your-own-key/oidc-configurations/aws
1114
type AWSOIDCConfigurations interface {
1215
Create(ctx context.Context, organization string, options AWSOIDCConfigurationCreateOptions) (*AWSOIDCConfiguration, error)
1316

azure_oidc_configuration.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ import (
66
"net/url"
77
)
88

9+
// AzureOIDCConfigurations describes all the Azure OIDC configuration related methods that the HCP Terraform API supports.
10+
// HCP Terraform API docs:
11+
// https://developer.hashicorp.com/terraform/cloud-docs/api-docs/hold-your-own-key/oidc-configurations/azure
912
type AzureOIDCConfigurations interface {
1013
Create(ctx context.Context, organization string, options AzureOIDCConfigurationCreateOptions) (*AzureOIDCConfiguration, error)
1114

errors.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,10 @@ var (
244244
ErrInvalidOIDC = errors.New("invalid value for OIDC configuration ID")
245245

246246
ErrInvalidHYOK = errors.New("invalid value for HYOK configuration ID")
247+
248+
ErrInvalidHYOKCustomerKeyVersion = errors.New("invalid value for HYOK Customer key version ID")
249+
250+
ErrInvalidHYOKEncryptedDataKey = errors.New("invalid value for HYOK encrypted data key ID")
247251
)
248252

249253
var (

gcp_oidc_configuration.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ import (
66
"net/url"
77
)
88

9+
// GCPOIDCConfigurations describes all the GCP OIDC configuration related methods that the HCP Terraform API supports.
10+
// HCP Terraform API docs:
11+
// https://developer.hashicorp.com/terraform/cloud-docs/api-docs/hold-your-own-key/oidc-configurations/gcp
912
type GCPOIDCConfigurations interface {
1013
Create(ctx context.Context, organization string, options GCPOIDCConfigurationCreateOptions) (*GCPOIDCConfiguration, error)
1114

hyok_configuration.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ import (
66
"net/url"
77
)
88

9+
// HYOKConfigurations describes all the HYOK configuration related methods that the HCP Terraform API supports.
10+
// HCP Terraform API docs:
11+
// https://developer.hashicorp.com/terraform/cloud-docs/api-docs/hold-your-own-key/configurations
912
type HYOKConfigurations interface {
1013
List(ctx context.Context, organization string, options *HYOKConfigurationsListOptions) (*HYOKConfigurationsList, error)
1114

@@ -72,6 +75,7 @@ type HYOKConfiguration struct {
7275
Organization *Organization `jsonapi:"relation,organization"`
7376
OIDCConfiguration *OIDCConfigurationTypeChoice `jsonapi:"polyrelation,oidc-configuration"`
7477
AgentPool *AgentPool `jsonapi:"relation,agent-pool"`
78+
KeyVersions []*HYOKCustomerKeyVersion `jsonapi:"relation,hyok-customer-key-versions"`
7579
}
7680

7781
type HYOKConfigurationsList struct {

hyok_customer_key_version.go

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
package tfe
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"net/url"
7+
"time"
8+
)
9+
10+
var _ HYOKCustomerKeyVersions = (*hyokCustomerKeyVersions)(nil)
11+
12+
// HYOKCustomerKeyVersions describes all the hyok customer key version related methods that the HCP Terraform API supports.
13+
// HCP Terraform API docs:
14+
// https://developer.hashicorp.com/terraform/cloud-docs/api-docs/hold-your-own-key/key-versions
15+
type HYOKCustomerKeyVersions interface {
16+
// List all hyok customer key versions associated to a HYOK configuration.
17+
List(ctx context.Context, hyokConfigurationID string, options *HYOKCustomerKeyVersionListOptions) (*HYOKCustomerKeyVersionList, error)
18+
19+
// Read a hyok customer key version by its ID.
20+
Read(ctx context.Context, hyokCustomerKeyVersionID string) (*HYOKCustomerKeyVersion, error)
21+
22+
// Revoke a hyok customer key version.
23+
Revoke(ctx context.Context, hyokCustomerKeyVersionID string) error
24+
25+
// Delete a hyok customer key version.
26+
Delete(ctx context.Context, hyokCustomerKeyVersionID string) error
27+
}
28+
29+
// hyokCustomerKeyVersions implements HYOKCustomerKeyVersions
30+
type hyokCustomerKeyVersions struct {
31+
client *Client
32+
}
33+
34+
// HYOKCustomerKeyVersionList represents a list of hyok customer key versions
35+
type HYOKCustomerKeyVersionList struct {
36+
*Pagination
37+
Items []*HYOKCustomerKeyVersion
38+
}
39+
40+
// HYOKCustomerKeyVersion represents the resource
41+
type HYOKCustomerKeyVersion struct {
42+
// Attributes
43+
ID string `jsonapi:"primary,hyok-customer-key-versions"`
44+
KeyVersion string `jsonapi:"attr,key-version"`
45+
CreatedAt time.Time `jsonapi:"attr,created-at,iso8601"`
46+
UpdatedAt time.Time `jsonapi:"attr,updated-at,iso8601"`
47+
RevokedAt time.Time `jsonapi:"attr,revoked-at,iso8601"`
48+
Status HYOKKeyVersionStatus `jsonapi:"attr,status"`
49+
Error string `jsonapi:"attr,error"`
50+
51+
// Relationships
52+
HYOKConfiguration *HYOKConfiguration `jsonapi:"relation,hyok-configuration"`
53+
}
54+
55+
// HYOKKeyVersionStatus represents a key version status.
56+
type HYOKKeyVersionStatus string
57+
58+
// List all available configuration version statuses.
59+
const (
60+
KeyVersionStatusAvailable HYOKKeyVersionStatus = "available"
61+
KeyVersionStatusRevoking HYOKKeyVersionStatus = "revoking"
62+
KeyVersionStatusRevoked HYOKKeyVersionStatus = "revoked"
63+
KeyVersionStatusRevocationFailed HYOKKeyVersionStatus = "revocation_failed"
64+
)
65+
66+
// HYOKCustomerKeyVersionListOptions represents the options for listing hyok customer key versions
67+
type HYOKCustomerKeyVersionListOptions struct {
68+
ListOptions
69+
Refresh bool `url:"refresh,omitempty"`
70+
}
71+
72+
// List all hyok customer key versions.
73+
func (s *hyokCustomerKeyVersions) List(ctx context.Context, hyokConfigurationID string, options *HYOKCustomerKeyVersionListOptions) (*HYOKCustomerKeyVersionList, error) {
74+
if !validStringID(&hyokConfigurationID) {
75+
return nil, ErrInvalidHYOK
76+
}
77+
78+
path := fmt.Sprintf("hyok-configurations/%s/hyok-customer-key-versions", url.PathEscape(hyokConfigurationID))
79+
req, err := s.client.NewRequest("GET", path, options)
80+
if err != nil {
81+
return nil, err
82+
}
83+
84+
kvs := &HYOKCustomerKeyVersionList{}
85+
err = req.Do(ctx, kvs)
86+
if err != nil {
87+
return nil, err
88+
}
89+
90+
return kvs, nil
91+
}
92+
93+
// Read a hyok customer key version by its ID.
94+
func (s *hyokCustomerKeyVersions) Read(ctx context.Context, hyokCustomerKeyVersionID string) (*HYOKCustomerKeyVersion, error) {
95+
if !validStringID(&hyokCustomerKeyVersionID) {
96+
return nil, ErrInvalidHYOKCustomerKeyVersion
97+
}
98+
99+
path := fmt.Sprintf("hyok-customer-key-versions/%s", url.PathEscape(hyokCustomerKeyVersionID))
100+
req, err := s.client.NewRequest("GET", path, nil)
101+
if err != nil {
102+
return nil, err
103+
}
104+
105+
kv := &HYOKCustomerKeyVersion{}
106+
err = req.Do(ctx, kv)
107+
if err != nil {
108+
return nil, err
109+
}
110+
111+
return kv, nil
112+
}
113+
114+
// Revoke a hyok customer key version. This process is asynchronous.
115+
// Returns `error` if there was a problem triggering the revocation. Otherwise revocation has been triggered successfully.
116+
func (s *hyokCustomerKeyVersions) Revoke(ctx context.Context, hyokCustomerKeyVersionID string) error {
117+
if !validStringID(&hyokCustomerKeyVersionID) {
118+
return ErrInvalidHYOKCustomerKeyVersion
119+
}
120+
121+
path := fmt.Sprintf("hyok-customer-key-versions/%s/actions/revoke", url.PathEscape(hyokCustomerKeyVersionID))
122+
req, err := s.client.NewRequest("POST", path, nil)
123+
if err != nil {
124+
return err
125+
}
126+
127+
return req.Do(ctx, nil)
128+
}
129+
130+
// Delete a hyok customer key version.
131+
func (s *hyokCustomerKeyVersions) Delete(ctx context.Context, hyokCustomerKeyVersionID string) error {
132+
if !validStringID(&hyokCustomerKeyVersionID) {
133+
return ErrInvalidHYOKCustomerKeyVersion
134+
}
135+
136+
path := fmt.Sprintf("hyok-customer-key-versions/%s", url.PathEscape(hyokCustomerKeyVersionID))
137+
req, err := s.client.NewRequest("DELETE", path, nil)
138+
if err != nil {
139+
return err
140+
}
141+
142+
return req.Do(ctx, nil)
143+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package tfe
2+
3+
import (
4+
"context"
5+
"testing"
6+
7+
"github.com/stretchr/testify/require"
8+
)
9+
10+
// These tests are intended for local execution only, as key versions for HYOK requires specific conditions
11+
// for tests to run successfully. To test locally:
12+
// 1. Follow the instructions outlined in hyok_configuration_integration_test.go.
13+
// 2. Set hyokCustomerKeyVersionID to the ID of an existing HYOK customer key version
14+
15+
func TestHYOKCustomerKeyVersionsList(t *testing.T) {
16+
if skipHYOKIntegrationTests {
17+
t.Skip()
18+
}
19+
20+
client := testClient(t)
21+
ctx := context.Background()
22+
23+
orgTest, err := client.Organizations.Read(ctx, hyokOrganizationName)
24+
if err != nil {
25+
t.Fatal(err)
26+
}
27+
28+
agentPool, agentPoolCleanup := createAgentPool(t, client, orgTest)
29+
t.Cleanup(agentPoolCleanup)
30+
31+
oidc, oidcCleanup := createGCPOIDCConfiguration(t, client, orgTest)
32+
t.Cleanup(oidcCleanup)
33+
hyok, hyokCleanup := oidc.createHYOKConfiguration(t, client, orgTest, agentPool)
34+
t.Cleanup(hyokCleanup)
35+
36+
t.Run("with no list options", func(t *testing.T) {
37+
_, err := client.HYOKCustomerKeyVersions.List(ctx, hyok.ID, nil)
38+
require.NoError(t, err)
39+
})
40+
}
41+
42+
func TestHYOKCustomerKeyVersionsRead(t *testing.T) {
43+
if skipHYOKIntegrationTests {
44+
t.Skip()
45+
}
46+
47+
client := testClient(t)
48+
ctx := context.Background()
49+
50+
t.Run("read an existing key version", func(t *testing.T) {
51+
hyokCustomerKeyVersionID := ""
52+
_, err := client.HYOKCustomerKeyVersions.Read(ctx, hyokCustomerKeyVersionID)
53+
require.NoError(t, err)
54+
})
55+
}

hyok_encrypted_data_key.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package tfe
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"net/url"
7+
"time"
8+
)
9+
10+
var _ HYOKEncryptedDataKeys = (*hyokEncryptedDataKeys)(nil)
11+
12+
// HYOKEncryptedDataKeys describes all the hyok customer key version related methods that the HCP Terraform API supports.
13+
// HCP Terraform API docs:
14+
// https://developer.hashicorp.com/terraform/cloud-docs/api-docs/hold-your-own-key/encrypted-data-keys
15+
type HYOKEncryptedDataKeys interface {
16+
// Read a HYOK encrypted data key by its ID.
17+
Read(ctx context.Context, hyokEncryptedDataKeyID string) (*HYOKEncryptedDataKey, error)
18+
}
19+
20+
// hyokEncryptedDataKeys implements HYOKEncryptedDataKeys
21+
type hyokEncryptedDataKeys struct {
22+
client *Client
23+
}
24+
25+
// HYOKEncryptedDataKey represents the resource
26+
type HYOKEncryptedDataKey struct {
27+
// Attributes
28+
ID string `jsonapi:"primary,hyok-encrypted-data-keys"`
29+
EncryptedDEK string `jsonapi:"attr,encrypted-dek"`
30+
CustomerKeyName string `jsonapi:"attr,customer-key-name"`
31+
CreatedAt time.Time `jsonapi:"attr,created-at,iso8601"`
32+
33+
// Relationships
34+
KeyVersion *HYOKCustomerKeyVersion `jsonapi:"relation,hyok-customer-key-versions"`
35+
}
36+
37+
// Read a HYOK encrypted data key by its ID.
38+
func (h hyokEncryptedDataKeys) Read(ctx context.Context, hyokEncryptedDataKeyID string) (*HYOKEncryptedDataKey, error) {
39+
if !validStringID(&hyokEncryptedDataKeyID) {
40+
return nil, ErrInvalidHYOKEncryptedDataKey
41+
}
42+
43+
path := fmt.Sprintf("hyok-encrypted-data-keys/%s", url.PathEscape(hyokEncryptedDataKeyID))
44+
req, err := h.client.NewRequest("GET", path, nil)
45+
if err != nil {
46+
return nil, err
47+
}
48+
49+
dek := &HYOKEncryptedDataKey{}
50+
err = req.Do(ctx, dek)
51+
if err != nil {
52+
return nil, err
53+
}
54+
55+
return dek, nil
56+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package tfe
2+
3+
import (
4+
"context"
5+
"testing"
6+
7+
"github.com/stretchr/testify/require"
8+
)
9+
10+
// These tests are intended for local execution only, as data encryption keys for HYOK requires specific conditions
11+
// for tests to run successfully. To test locally:
12+
// 1. Follow the instructions outlined in hyok_configuration_integration_test.go.
13+
// 2. Set hyokEncryptedDataKeyID to the ID of an existing data encryption key
14+
15+
func TestHYOKEncryptedDataKeyRead(t *testing.T) {
16+
if skipHYOKIntegrationTests {
17+
t.Skip()
18+
}
19+
20+
client := testClient(t)
21+
ctx := context.Background()
22+
23+
t.Run("read an existing encrypted data key", func(t *testing.T) {
24+
hyokEncryptedDataKeyID := ""
25+
_, err := client.HYOKEncryptedDataKeys.Read(ctx, hyokEncryptedDataKeyID)
26+
require.NoError(t, err)
27+
})
28+
}

tfe.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,8 @@ type Client struct {
170170
SSHKeys SSHKeys
171171
Stacks Stacks
172172
HYOKConfigurations HYOKConfigurations
173+
HYOKCustomerKeyVersions HYOKCustomerKeyVersions
174+
HYOKEncryptedDataKeys HYOKEncryptedDataKeys
173175
StackConfigurations StackConfigurations
174176
StackDeployments StackDeployments
175177
StackDeploymentGroups StackDeploymentGroups
@@ -509,6 +511,8 @@ func NewClient(cfg *Config) (*Client, error) {
509511
client.SSHKeys = &sshKeys{client: client}
510512
client.Stacks = &stacks{client: client}
511513
client.HYOKConfigurations = &hyokConfigurations{client: client}
514+
client.HYOKCustomerKeyVersions = &hyokCustomerKeyVersions{client: client}
515+
client.HYOKEncryptedDataKeys = &hyokEncryptedDataKeys{client: client}
512516
client.StackConfigurations = &stackConfigurations{client: client}
513517
client.StackDeployments = &stackDeployments{client: client}
514518
client.StackDeploymentGroups = &stackDeploymentGroups{client: client}

0 commit comments

Comments
 (0)