Skip to content

Commit

Permalink
Merge pull request #376 from smallstep/fix-363
Browse files Browse the repository at this point in the history
Add a configurable retention period for cloudkms keys
  • Loading branch information
maraino authored Nov 29, 2023
2 parents 02fad72 + 50165c5 commit 198f630
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 5 deletions.
7 changes: 7 additions & 0 deletions kms/apiv1/requests.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"crypto"
"crypto/x509"
"fmt"
"time"
)

// ProtectionLevel specifies on some KMS how cryptographic operations are
Expand Down Expand Up @@ -160,6 +161,12 @@ type CreateKeyRequest struct {
//
// Used by: yubikey
TouchPolicy TouchPolicy

// DestroyRetentionPeriod is the period of time that a key spends in a
// destroy scheduled state before transitioning to destroyed.
//
// Used by: cloudkms
DestroyRetentionPeriod time.Duration
}

// CreateKeyResponse is the response value of the kms.CreateKey method.
Expand Down
9 changes: 8 additions & 1 deletion kms/cloudkms/cloudkms.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (

"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/durationpb"

cloudkms "cloud.google.com/go/kms/apiv1"
"cloud.google.com/go/kms/apiv1/kmspb"
Expand Down Expand Up @@ -188,7 +189,10 @@ func (k *CloudKMS) CreateKey(req *apiv1.CreateKeyRequest) (*apiv1.CreateKeyRespo
return nil, errors.Errorf("unexpected error: this should not happen")
}

var crytoKeyName string
var destroyScheduledDuration *durationpb.Duration
if req.DestroyRetentionPeriod > 0 {
destroyScheduledDuration = durationpb.New(req.DestroyRetentionPeriod)
}

// resource is the plain Google Cloud KMS resource name
resource := resourceName(req.Name)
Expand All @@ -200,6 +204,8 @@ func (k *CloudKMS) CreateKey(req *apiv1.CreateKeyRequest) (*apiv1.CreateKeyRespo
return nil, err
}

var crytoKeyName string

ctx, cancel := defaultContext()
defer cancel()

Expand All @@ -213,6 +219,7 @@ func (k *CloudKMS) CreateKey(req *apiv1.CreateKeyRequest) (*apiv1.CreateKeyRespo
ProtectionLevel: protectionLevel,
Algorithm: signatureAlgorithm,
},
DestroyScheduledDuration: destroyScheduledDuration,
},
})
if err != nil {
Expand Down
13 changes: 9 additions & 4 deletions kms/cloudkms/cloudkms_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,18 @@ import (
"os"
"reflect"
"testing"
"time"

"cloud.google.com/go/kms/apiv1/kmspb"
gax "github.com/googleapis/gax-go/v2"
"github.com/stretchr/testify/assert"
"go.step.sm/crypto/kms/apiv1"
"go.step.sm/crypto/kms/uri"
"go.step.sm/crypto/pemutil"
"google.golang.org/api/option"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/durationpb"
)

func TestParent(t *testing.T) {
Expand Down Expand Up @@ -262,7 +265,8 @@ func TestCloudKMS_CreateKey(t *testing.T) {
getKeyRing: func(_ context.Context, _ *kmspb.GetKeyRingRequest, _ ...gax.CallOption) (*kmspb.KeyRing, error) {
return &kmspb.KeyRing{}, nil
},
createCryptoKey: func(_ context.Context, _ *kmspb.CreateCryptoKeyRequest, _ ...gax.CallOption) (*kmspb.CryptoKey, error) {
createCryptoKey: func(_ context.Context, req *kmspb.CreateCryptoKeyRequest, _ ...gax.CallOption) (*kmspb.CryptoKey, error) {
assert.Nil(t, req.CryptoKey.DestroyScheduledDuration)
return &kmspb.CryptoKey{Name: keyName}, nil
},
getPublicKey: func(_ context.Context, _ *kmspb.GetPublicKeyRequest, _ ...gax.CallOption) (*kmspb.PublicKey, error) {
Expand All @@ -271,19 +275,20 @@ func TestCloudKMS_CreateKey(t *testing.T) {
}},
args{&apiv1.CreateKeyRequest{Name: keyName, ProtectionLevel: apiv1.HSM, SignatureAlgorithm: apiv1.ECDSAWithSHA256}},
&apiv1.CreateKeyResponse{Name: "cloudkms:" + keyName + "/cryptoKeyVersions/1", PublicKey: pk, CreateSignerRequest: apiv1.CreateSignerRequest{SigningKey: "cloudkms:" + keyName + "/cryptoKeyVersions/1"}}, false},
{"ok with uri", fields{
{"ok with uri and retention", fields{
&MockClient{
getKeyRing: func(_ context.Context, _ *kmspb.GetKeyRingRequest, _ ...gax.CallOption) (*kmspb.KeyRing, error) {
return &kmspb.KeyRing{}, nil
},
createCryptoKey: func(_ context.Context, _ *kmspb.CreateCryptoKeyRequest, _ ...gax.CallOption) (*kmspb.CryptoKey, error) {
createCryptoKey: func(_ context.Context, req *kmspb.CreateCryptoKeyRequest, _ ...gax.CallOption) (*kmspb.CryptoKey, error) {
assert.Equal(t, req.CryptoKey.DestroyScheduledDuration, durationpb.New(24*time.Hour))
return &kmspb.CryptoKey{Name: keyName}, nil
},
getPublicKey: func(_ context.Context, _ *kmspb.GetPublicKeyRequest, _ ...gax.CallOption) (*kmspb.PublicKey, error) {
return &kmspb.PublicKey{Pem: string(pemBytes)}, nil
},
}},
args{&apiv1.CreateKeyRequest{Name: keyURI, ProtectionLevel: apiv1.HSM, SignatureAlgorithm: apiv1.ECDSAWithSHA256}},
args{&apiv1.CreateKeyRequest{Name: keyURI, ProtectionLevel: apiv1.HSM, SignatureAlgorithm: apiv1.ECDSAWithSHA256, DestroyRetentionPeriod: 24 * time.Hour}},
&apiv1.CreateKeyResponse{Name: "cloudkms:" + keyName + "/cryptoKeyVersions/1", PublicKey: pk, CreateSignerRequest: apiv1.CreateSignerRequest{SigningKey: "cloudkms:" + keyName + "/cryptoKeyVersions/1"}}, false},
{"ok new key ring", fields{
&MockClient{
Expand Down

0 comments on commit 198f630

Please sign in to comment.