Skip to content

Commit b4107fe

Browse files
authored
Merge pull request #2114 from Tiime-Software/feat/gcpkms-sovereign-cloud-endpoint
Add SOPS_GCP_KMS_ENDPOINT and SOPS_GCP_KMS_UNIVERSE_DOMAIN env vars
2 parents a5a8706 + 306d98d commit b4107fe

3 files changed

Lines changed: 54 additions & 0 deletions

File tree

README.rst

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,20 @@ switch to the REST client by setting the ``SOPS_GCP_KMS_CLIENT_TYPE`` environmen
325325
$ export SOPS_GCP_KMS_CLIENT_TYPE=rest # Use REST client
326326
$ export SOPS_GCP_KMS_CLIENT_TYPE=grpc # Use gRPC client (default)
327327
328+
For sovereign cloud environments that expose a GCP-compatible KMS API at a
329+
non-standard endpoint (e.g. S3NS/Thales TPC: ``cloudkms.s3nsapis.fr``),
330+
you can override the endpoint or the universe domain:
331+
332+
.. code:: sh
333+
334+
# Override the KMS endpoint directly
335+
$ export SOPS_GCP_KMS_ENDPOINT=cloudkms.example.com:443
336+
337+
# Or derive the endpoint from the universe domain (cloudkms.<domain>:443)
338+
$ export SOPS_GCP_KMS_UNIVERSE_DOMAIN=example.com
339+
340+
.. note:: ``SOPS_GCP_KMS_ENDPOINT`` takes precedence over ``SOPS_GCP_KMS_UNIVERSE_DOMAIN`` if both are set.
341+
328342
Encrypting/decrypting with GCP KMS requires a KMS ResourceID. You can use the
329343
cloud console the get the ResourceID or you can create one using the gcloud
330344
sdk:

gcpkms/keysource.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,14 @@ const (
3030
// SopsGCPKMSClientTypeEnv is the environment variable used to specify the
3131
// GCP KMS client type. Valid values are "grpc" (default) and "rest".
3232
SopsGCPKMSClientTypeEnv = "SOPS_GCP_KMS_CLIENT_TYPE"
33+
// SopsGCPKMSEndpointEnv overrides the GCP KMS endpoint URL. Useful for
34+
// sovereign cloud environments that expose a GCP-compatible KMS API at a
35+
// non-standard endpoint (e.g. S3NS/Thales TPC: cloudkms.s3nsapis.fr).
36+
SopsGCPKMSEndpointEnv = "SOPS_GCP_KMS_ENDPOINT"
37+
// SopsGCPKMSUniverseDomainEnv sets the universe domain for the GCP KMS
38+
// client, which derives the endpoint as cloudkms.{UNIVERSE_DOMAIN}:443.
39+
// Example: "s3nsapis.fr" for S3NS/Thales TPC.
40+
SopsGCPKMSUniverseDomainEnv = "SOPS_GCP_KMS_UNIVERSE_DOMAIN"
3341
// KeyTypeIdentifier is the string used to identify a GCP KMS MasterKey.
3442
KeyTypeIdentifier = "gcp_kms"
3543
)
@@ -320,6 +328,12 @@ func (key *MasterKey) newKMSClient(ctx context.Context) (*kms.KeyManagementClien
320328
// Add extra options.
321329
opts = append(opts, key.clientOpts...)
322330

331+
if endpoint := os.Getenv(SopsGCPKMSEndpointEnv); endpoint != "" {
332+
opts = append(opts, option.WithEndpoint(endpoint))
333+
} else if ud := os.Getenv(SopsGCPKMSUniverseDomainEnv); ud != "" {
334+
opts = append(opts, option.WithUniverseDomain(ud))
335+
}
336+
323337
// Select client type based on inputs.
324338
clientType := strings.ToLower(os.Getenv(SopsGCPKMSClientTypeEnv))
325339
var client *kms.KeyManagementClient

gcpkms/keysource_test.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,32 @@ func TestMasterKey_createCloudKMSService_withoutCredentials(t *testing.T) {
189189
assert.ErrorContains(t, err, "credentials: could not find default credentials")
190190
}
191191

192+
func TestMasterKey_createCloudKMSService_withEndpointEnv(t *testing.T) {
193+
t.Setenv(SopsGCPKMSEndpointEnv, "cloudkms.example.com:443")
194+
t.Setenv(SopsGoogleCredentialsOAuthTokenEnv, "token")
195+
196+
masterKey := MasterKey{
197+
ResourceID: testResourceID,
198+
}
199+
200+
client, err := masterKey.newKMSClient(context.Background())
201+
assert.NoError(t, err)
202+
assert.Contains(t, client.Connection().Target(), "cloudkms.example.com")
203+
}
204+
205+
func TestMasterKey_createCloudKMSService_withUniverseDomainEnv(t *testing.T) {
206+
t.Setenv(SopsGCPKMSUniverseDomainEnv, "example.com")
207+
t.Setenv(SopsGoogleCredentialsOAuthTokenEnv, "token")
208+
209+
masterKey := MasterKey{
210+
ResourceID: testResourceID,
211+
}
212+
213+
client, err := masterKey.newKMSClient(context.Background())
214+
assert.NoError(t, err)
215+
assert.Contains(t, client.Connection().Target(), "cloudkms.example.com")
216+
}
217+
192218
func newGRPCServer(port string) *grpc.ClientConn {
193219
serv := grpc.NewServer()
194220
kmspb.RegisterKeyManagementServiceServer(serv, &mockKeyManagement)

0 commit comments

Comments
 (0)