Skip to content

feat(parametermanager): Added samples for kms_key in regional parameter #5262

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
021cd8b
feat(parametermanager): Added samples for kms_key in regional parameter
durgesh-ninave-crest Apr 7, 2025
759160c
Merge branch 'main' into parametermanager-regional-kms_key-samples
durgesh-ninave-crest Apr 9, 2025
e2bf56a
fix(parametermanager): fix linting issue
durgesh-ninave-crest Apr 9, 2025
79dbcb9
Merge branch 'main' into parametermanager-regional-kms_key-samples
durgesh-ninave-crest Apr 9, 2025
f8dfcf3
Merge branch 'main' into parametermanager-regional-kms_key-samples
durgesh-ninave-crest Apr 10, 2025
1ebd9d0
fix(parametermanager): Fix linting issue
durgesh-ninave-crest Apr 10, 2025
f44a7bf
fix(parametermanager): update variable's name
durgesh-ninave-crest Apr 10, 2025
ee7b02b
fix(parametermanager): regional test-case update variable's name
durgesh-ninave-crest Apr 10, 2025
f5aa8ca
Merge branch 'main' into parametermanager-regional-kms_key-samples
durgesh-ninave-crest Apr 14, 2025
13df36e
fix(parametermanager): update testcase, error message and godoc for c…
durgesh-ninave-crest Apr 14, 2025
ac0114c
Merge branch 'main' into parametermanager-regional-kms_key-samples
durgesh-ninave-crest Apr 15, 2025
f08613f
Merge branch 'main' into parametermanager-regional-kms_key-samples
durgesh-ninave-crest Apr 16, 2025
37c3d90
Merge branch 'main' into parametermanager-regional-kms_key-samples
durgesh-ninave-crest Apr 16, 2025
9a26195
Merge branch 'main' into parametermanager-regional-kms_key-samples
arpangoswami Apr 17, 2025
ac868e2
Merge branch 'main' into parametermanager-regional-kms_key-samples
durgesh-ninave-crest Apr 17, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion parametermanager/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ module github.com/GoogleCloudPlatform/golang-samples/parametermanager
go 1.23.0

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Consider using go 1.22 instead of go 1.23 to align with the go version used in other golang-samples, unless there is a specific reason to use go 1.23.


require (
cloud.google.com/go/kms v1.21.2
cloud.google.com/go/parametermanager v0.2.1
cloud.google.com/go/secretmanager v1.14.7
github.com/GoogleCloudPlatform/golang-samples v0.0.0-20250416173630-eafea413c9b7
github.com/GoogleCloudPlatform/golang-samples v0.0.0-20250417052308-a8d44a62f893
github.com/gofrs/uuid v4.4.0+incompatible
google.golang.org/api v0.229.0
google.golang.org/genproto v0.0.0-20250414145226-207652e42e2e
Expand All @@ -19,6 +20,7 @@ require (
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
cloud.google.com/go/compute/metadata v0.6.0 // indirect
cloud.google.com/go/iam v1.5.0 // indirect
cloud.google.com/go/longrunning v0.6.6 // indirect
cloud.google.com/go/monitoring v1.24.1 // indirect
cloud.google.com/go/storage v1.50.0 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0 // indirect
Expand Down
6 changes: 4 additions & 2 deletions parametermanager/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4
cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg=
cloud.google.com/go/iam v1.5.0 h1:QlLcVMhbLGOjRcGe6VTGGTyQib8dRLK2B/kYNV0+2xs=
cloud.google.com/go/iam v1.5.0/go.mod h1:U+DOtKQltF/LxPEtcDLoobcsZMilSRwR7mgNL7knOpo=
cloud.google.com/go/kms v1.21.2 h1:c/PRUSMNQ8zXrc1sdAUnsenWWaNXN+PzTXfXOcSFdoE=
cloud.google.com/go/kms v1.21.2/go.mod h1:8wkMtHV/9Z8mLXEXr1GK7xPSBdi6knuLXIhqjuWcI6w=
cloud.google.com/go/logging v1.13.0 h1:7j0HgAp0B94o1YRDqiqm26w4q1rDMH7XNRU34lJXHYc=
cloud.google.com/go/logging v1.13.0/go.mod h1:36CoKh6KA/M0PbhPKMq6/qety2DCAErbhXT62TuXALA=
cloud.google.com/go/longrunning v0.6.6 h1:XJNDo5MUfMM05xK3ewpbSdmt7R2Zw+aQEMbdQR65Rbw=
Expand All @@ -24,8 +26,8 @@ cloud.google.com/go/storage v1.50.0 h1:3TbVkzTooBvnZsk7WaAQfOsNrdoM8QHusXA1cpk6Q
cloud.google.com/go/storage v1.50.0/go.mod h1:l7XeiD//vx5lfqE3RavfmU9yvk5Pp0Zhcv482poyafY=
cloud.google.com/go/trace v1.11.5 h1:CALS1loyxJMnRiCwZSpdf8ac7iCsjreMxFD2WGxzzHU=
cloud.google.com/go/trace v1.11.5/go.mod h1:TwblCcqNInriu5/qzaeYEIH7wzUcchSdeY2l5wL3Eec=
github.com/GoogleCloudPlatform/golang-samples v0.0.0-20250416173630-eafea413c9b7 h1:nUDEfWIscFfFBcNTR5HIA3OswLZEPlGRHhAQ7v+2NEo=
github.com/GoogleCloudPlatform/golang-samples v0.0.0-20250416173630-eafea413c9b7/go.mod h1:pro/7J5Dd9+sI+NAZUopa1sW4YuthozUkor+3MF6fIU=
github.com/GoogleCloudPlatform/golang-samples v0.0.0-20250417052308-a8d44a62f893 h1:G6Dsf9L1SxjKpZB2gf4mykaXURpiEf4oJLLn/s170Ds=
github.com/GoogleCloudPlatform/golang-samples v0.0.0-20250417052308-a8d44a62f893/go.mod h1:pro/7J5Dd9+sI+NAZUopa1sW4YuthozUkor+3MF6fIU=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0 h1:3c8yed4lgqTt+oTQ+JNMDo+F4xprBf+O/il4ZC0nRLw=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0/go.mod h1:obipzmGjfSjam60XLwGfqUkJsfiheAl+TUjG+4yzyPM=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.50.0 h1:5IT7xOdq17MtcdtL/vtl6mGfzhaq4m4vpollPRmlsBQ=
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package regional_parametermanager

// [START parametermanager_create_regional_param_with_kms_key]
import (
"context"
"fmt"
"io"

parametermanager "cloud.google.com/go/parametermanager/apiv1"
parametermanagerpb "cloud.google.com/go/parametermanager/apiv1/parametermanagerpb"
"google.golang.org/api/option"
)

// createRegionalParamWithKmsKey creates a regional parameter with kms_key using the Parameter Manager SDK for GCP.
//
// w: The io.Writer object used to write the output.
// projectID: The ID of the project where the parameter is located.
// locationID: The ID of the location where the parameter is located.
// parameterID: The ID of the parameter to be created.
// kmsKey: The ID of the KMS key to be used for encryption.
// (e.g. "projects/my-project/locations/us-central1/keyRings/my-key-ring/cryptoKeys/my-encryption-key")
// (For more information, see: https://cloud.google.com/secret-manager/parameter-manager/docs/cmek)
//
// The function returns an error if the parameter creation fails.
func createRegionalParamWithKmsKey(w io.Writer, projectID, locationID, parameterID, kmsKey string) error {
// Create a context and a Parameter Manager client.
ctx := context.Background()

// Create a Parameter Manager client.
endpoint := fmt.Sprintf("parametermanager.%s.rep.googleapis.com:443", locationID)
client, err := parametermanager.NewClient(ctx, option.WithEndpoint(endpoint))
if err != nil {
return fmt.Errorf("failed to create Parameter Manager client: %w", err)
}
defer client.Close()

// Construct the name of the create parameter.
parent := fmt.Sprintf("projects/%s/locations/%s", projectID, locationID)

// Create a parameter with unformatted format.
req := &parametermanagerpb.CreateParameterRequest{
Parent: parent,
ParameterId: parameterID,
Parameter: &parametermanagerpb.Parameter{
Format: parametermanagerpb.ParameterFormat_UNFORMATTED,
KmsKey: &kmsKey,
},
}
parameter, err := client.CreateParameter(ctx, req)
if err != nil {
return fmt.Errorf("failed to create parameter: %w", err)
}

fmt.Fprintf(w, "Created regional parameter %s with kms_key %s\n", parameter.Name, *parameter.KmsKey)
return nil
}

// [END parametermanager_create_regional_param_with_kms_key]
208 changes: 208 additions & 0 deletions parametermanager/regional_samples/regional_parametermanager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import (
"testing"
"time"

kms "cloud.google.com/go/kms/apiv1"
"cloud.google.com/go/kms/apiv1/kmspb"
parametermanager "cloud.google.com/go/parametermanager/apiv1"
parametermanagerpb "cloud.google.com/go/parametermanager/apiv1/parametermanagerpb"
secretmanager "cloud.google.com/go/secretmanager/apiv1"
Expand Down Expand Up @@ -91,6 +93,37 @@ func testParameter(t *testing.T, projectID string, format parametermanagerpb.Par
return parameter, parameterID
}

// testParameterWithKmsKey creates a parameter with a KMS key in the specified GCP project.
// It returns the created parameter and its ID or fails the test if parameter creation fails.
func testParameterWithKmsKey(t *testing.T, projectID, kms_key string) (*parametermanagerpb.Parameter, string) {
t.Helper()
parameterID := testName(t)
locationId := testLocation(t)

ctx := context.Background()
endpoint := fmt.Sprintf("parametermanager.%s.rep.googleapis.com:443", locationId)
client, err := parametermanager.NewClient(ctx, option.WithEndpoint(endpoint))
if err != nil {
t.Fatalf("failed to create client: %v", err)
}
defer client.Close()

parent := fmt.Sprintf("projects/%s/locations/%s", projectID, locationId)
parameter, err := client.CreateParameter(ctx, &parametermanagerpb.CreateParameterRequest{
Parent: parent,
ParameterId: parameterID,
Parameter: &parametermanagerpb.Parameter{
Format: parametermanagerpb.ParameterFormat_UNFORMATTED,
KmsKey: &kms_key,
},
})
if err != nil {
t.Fatalf("testParameter: failed to create parameter: %v", err)
}

return parameter, parameterID
}

// testParameterVersion creates a version of a parameter with the given payload in the specified GCP project.
// It returns the created parameter version and its ID or fails the test if parameter version creation fails.
func testParameterVersion(t *testing.T, projectID, parameterID, payload string) (*parametermanagerpb.ParameterVersion, string) {
Expand Down Expand Up @@ -281,6 +314,105 @@ func testCleanupSecret(t *testing.T, name string) {
}
}

// testCleanupKeyVersions deletes the specified key version in the GCP project.
// It fails the test if the key version deletion fails.
func testCleanupKeyVersions(t *testing.T, name string) {
t.Helper()
ctx := context.Background()

client, err := kms.NewKeyManagementClient(ctx)
if err != nil {
t.Fatalf("failed to create client: %v", err)
}
defer client.Close()

if _, err := client.DestroyCryptoKeyVersion(ctx, &kmspb.DestroyCryptoKeyVersionRequest{
Name: name,
}); err != nil {
if terr, ok := grpcstatus.FromError(err); !ok || terr.Code() != grpccodes.NotFound {
t.Fatalf("testCleanupKeyVersion: failed to delete key version: %v", err)
}
}
Comment on lines +317 to +335

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The DestroyCryptoKeyVersion method is used to delete key versions, but this operation is not directly supported. Instead, the crypto key itself should be disabled or destroyed. Consider updating this function to disable or destroy the crypto key instead of attempting to delete the key version, as this is the correct way to clean up the KMS resources.

}

// testCreateKeyRing creates a key ring in the specified GCP project.
// It fails the test if the key ring creation fails.
func testCreateKeyRing(t *testing.T, projectID, keyRingId string) {
t.Helper()
ctx := context.Background()
locationID := testLocation(t)

client, err := kms.NewKeyManagementClient(ctx)
if err != nil {
t.Fatalf("failed to create client: %v", err)
}
defer client.Close()

parent := fmt.Sprintf("projects/%s/locations/%s", projectID, locationID)

// Check if key ring already exists
req := &kmspb.GetKeyRingRequest{
Name: parent + "/keyRings/" + keyRingId,
}
_, err = client.GetKeyRing(ctx, req)
if err != nil {
if terr, ok := grpcstatus.FromError(err); !ok || terr.Code() != grpccodes.NotFound {
t.Fatalf("failed to get key ring: %v", err)
}
// Key ring not found, create it
req := &kmspb.CreateKeyRingRequest{
Parent: parent,
KeyRingId: keyRingId,
}
_, err = client.CreateKeyRing(ctx, req)
if err != nil {
t.Fatalf("failed to create key ring: %v", err)
}
}
Comment on lines +353 to +371

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The test functions testCreateKeyRing and testCreateKeyHSM check if the key ring and key already exist before creating them. However, the check is performed by attempting to get the resource and handling a NotFound error. This approach is less efficient than using a dedicated "exists" check if available in the API. Consider using a more efficient method to check for the existence of the resources before attempting to create them.

}

// testCreateKeyHSM creates a HSM key in the specified key ring in the GCP project.
// It fails the test if the key creation fails.
func testCreateKeyHSM(t *testing.T, projectID, keyRing, id string) {
t.Helper()
ctx := context.Background()
locationID := testLocation(t)
client, err := kms.NewKeyManagementClient(ctx)
if err != nil {
t.Fatalf("failed to create client: %v", err)
}
defer client.Close()

parent := fmt.Sprintf("projects/%s/locations/%s/keyRings/%s", projectID, locationID, keyRing)

// Check if key already exists
req := &kmspb.GetCryptoKeyRequest{
Name: parent + "/cryptoKeys/" + id,
}
_, err = client.GetCryptoKey(ctx, req)
if err != nil {
if terr, ok := grpcstatus.FromError(err); !ok || terr.Code() != grpccodes.NotFound {
t.Fatalf("failed to get crypto key: %v", err)
}
// Key not found, create it
req := &kmspb.CreateCryptoKeyRequest{
Parent: parent,
CryptoKeyId: id,
CryptoKey: &kmspb.CryptoKey{
Purpose: kmspb.CryptoKey_ENCRYPT_DECRYPT,
VersionTemplate: &kmspb.CryptoKeyVersionTemplate{
ProtectionLevel: kmspb.ProtectionLevel_HSM,
Algorithm: kmspb.CryptoKeyVersion_GOOGLE_SYMMETRIC_ENCRYPTION,
},
},
}
_, err = client.CreateCryptoKey(ctx, req)
if err != nil {
t.Fatalf("failed to create crypto key: %v", err)
}
}
}

// TestCreateRegionalParam tests the createRegionalParam function by creating a regional parameter,
// then verifies if the parameter was successfully created by checking the output.
func TestCreateRegionalParam(t *testing.T) {
Expand Down Expand Up @@ -610,3 +742,79 @@ func TestListRegionalParamVersion(t *testing.T) {
t.Errorf("ListParameterVersion: expected %q to contain %q", got, want)
}
}

// TestCreateRegionalParamWithKmsKey tests the createRegionalParamWithKmsKey function by creating a regional parameter with a KMS key,
// and verifies if the parameter was successfully created by checking the output.
func TestCreateRegionalParamWithKmsKey(t *testing.T) {
tc := testutil.SystemTest(t)

parameterID := testName(t)
locationID := testLocation(t)
parameterName := fmt.Sprintf("projects/%s/locations/%s/parameters/%s", tc.ProjectID, locationID, parameterID)

keyId := testName(t)
testCreateKeyRing(t, tc.ProjectID, "go-test-key-ring")
testCreateKeyHSM(t, tc.ProjectID, "go-test-key-ring", keyId)
kms_key := fmt.Sprintf("projects/%s/locations/%s/keyRings/go-test-key-ring/cryptoKeys/%s", tc.ProjectID, locationID, keyId)

defer testCleanupParameter(t, parameterName)
defer testCleanupKeyVersions(t, fmt.Sprintf("%s/cryptoKeyVersions/1", kms_key))

var buf bytes.Buffer
if err := createRegionalParamWithKmsKey(&buf, tc.ProjectID, locationID, parameterID, kms_key); err != nil {
t.Fatalf("Failed to create regional parameter: %v", err)
}
if got, want := buf.String(), fmt.Sprintf("Created regional parameter %s with kms_key %s", parameterName, kms_key); !strings.Contains(got, want) {
t.Errorf("createParameter: expected %q to contain %q", got, want)
}
}

// TestUpdateRegionalParamKmsKey tests the updateRegionalParamKmsKey function by creating a regional parameter with a KMS key,
// updating the KMS key, and verifying if the parameter was successfully updated by checking the output.
func TestUpdateRegionalParamKmsKey(t *testing.T) {
tc := testutil.SystemTest(t)

locationID := testLocation(t)

keyId := testName(t)
testCreateKeyRing(t, tc.ProjectID, "go-test-key-ring")
testCreateKeyHSM(t, tc.ProjectID, "go-test-key-ring", keyId)
kms_key := fmt.Sprintf("projects/%s/locations/%s/keyRings/go-test-key-ring/cryptoKeys/%s", tc.ProjectID, locationID, keyId)

parameter, parameterID := testParameterWithKmsKey(t, tc.ProjectID, kms_key)
defer testCleanupParameter(t, parameter.Name)
defer testCleanupKeyVersions(t, fmt.Sprintf("%s/cryptoKeyVersions/1", kms_key))

var buf bytes.Buffer
if err := updateRegionalParamKmsKey(&buf, tc.ProjectID, locationID, parameterID, kms_key); err != nil {
t.Fatalf("Failed to update regional parameter: %v", err)
}
if got, want := buf.String(), fmt.Sprintf("Updated regional parameter %s with kms_key %s", parameter.Name, kms_key); !strings.Contains(got, want) {
t.Errorf("createParameter: expected %q to contain %q", got, want)
}
}

// TestRemoveRegionalParamKmsKey tests the removeRegionalParamKmsKey function by creating a regional parameter with a KMS key,
// removing the KMS key, and verifying if the KMS key was successfully removed by checking the output.
func TestRemoveRegionalParamKmsKey(t *testing.T) {
tc := testutil.SystemTest(t)

locationID := testLocation(t)

keyId := testName(t)
testCreateKeyRing(t, tc.ProjectID, "go-test-key-ring")
testCreateKeyHSM(t, tc.ProjectID, "go-test-key-ring", keyId)
kms_key := fmt.Sprintf("projects/%s/locations/%s/keyRings/go-test-key-ring/cryptoKeys/%s", tc.ProjectID, locationID, keyId)

parameter, parameterID := testParameterWithKmsKey(t, tc.ProjectID, kms_key)
defer testCleanupParameter(t, parameter.Name)
defer testCleanupKeyVersions(t, fmt.Sprintf("%s/cryptoKeyVersions/1", kms_key))

var buf bytes.Buffer
if err := removeRegionalParamKmsKey(&buf, tc.ProjectID, locationID, parameterID); err != nil {
t.Fatalf("Failed to create regional parameter: %v", err)
}
if got, want := buf.String(), fmt.Sprintf("Removed kms_key for regional parameter %s", parameter.Name); !strings.Contains(got, want) {
t.Errorf("createParameter: expected %q to contain %q", got, want)
}
}
Loading
Loading