mirror of
https://github.com/getsops/sops.git
synced 2026-02-05 12:45:21 +01:00
Support GOOGLE_OAUTH_ACCESS_TOKEN for GCP
Co-authored-by: Maren Sofie Ringsby <marensofieringsby@gmail.com> Co-authored-by: Matheus Pimenta <matheuscscp@gmail.com> Co-authored-by: Felix Fontein <felix@fontein.de> Signed-off-by: Hidde Beydals <hidde@hhh.computer>
This commit is contained in:
20
README.rst
20
README.rst
@@ -266,8 +266,12 @@ It is also possible to use ``updatekeys``, when adding or removing age recipient
|
||||
|
||||
Encrypting using GCP KMS
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
GCP KMS uses `Application Default Credentials
|
||||
<https://developers.google.com/identity/protocols/application-default-credentials>`_.
|
||||
GCP KMS has support for authorization with the use of `Application Default Credentials
|
||||
<https://developers.google.com/identity/protocols/application-default-credentials>`_ and using an OAuth 2.0 token.
|
||||
Application default credentials precedes the use of access token.
|
||||
|
||||
Using Application Default Credentials you can authorize by doing this:
|
||||
|
||||
If you already logged in using
|
||||
|
||||
.. code:: sh
|
||||
@@ -280,6 +284,18 @@ you can enable application default credentials using the sdk:
|
||||
|
||||
$ gcloud auth application-default login
|
||||
|
||||
Using OAauth tokens you can authorize by doing this:
|
||||
|
||||
.. code:: sh
|
||||
|
||||
$ export GOOGLE_OAUTH_ACCESS_TOKEN=<your access token>
|
||||
|
||||
Or if you are logged in you can authorize by generating an access token:
|
||||
|
||||
.. code:: sh
|
||||
|
||||
$ export GOOGLE_OAUTH_ACCESS_TOKEN="$(gcloud auth print-access-token)"
|
||||
|
||||
Encrypting/decrypting with GCP KMS requires a KMS ResourceID. You can use the
|
||||
cloud console the get the ResourceID or you can create one using the gcloud
|
||||
sdk:
|
||||
|
||||
@@ -24,6 +24,9 @@ const (
|
||||
// a path to a credentials file, or directly as the variable's value in JSON
|
||||
// format.
|
||||
SopsGoogleCredentialsEnv = "GOOGLE_CREDENTIALS"
|
||||
// SopsGoogleCredentialsOAuthTokenEnv is the environment variable used for the
|
||||
// GCP OAuth 2.0 Token.
|
||||
SopsGoogleCredentialsOAuthTokenEnv = "GOOGLE_OAUTH_ACCESS_TOKEN"
|
||||
// KeyTypeIdentifier is the string used to identify a GCP KMS MasterKey.
|
||||
KeyTypeIdentifier = "gcp_kms"
|
||||
)
|
||||
@@ -245,12 +248,19 @@ func (key *MasterKey) newKMSClient() (*kms.KeyManagementClient, error) {
|
||||
default:
|
||||
credentials, err := getGoogleCredentials()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("credentials: failed to obtain credentials from %q: %w", SopsGoogleCredentialsEnv, err)
|
||||
}
|
||||
if credentials != nil {
|
||||
opts = append(opts, option.WithCredentialsJSON(credentials))
|
||||
break
|
||||
}
|
||||
|
||||
if atCredentials := getGoogleOAuthTokenFromEnv(); atCredentials != nil {
|
||||
opts = append(opts, option.WithTokenSource(atCredentials))
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if key.grpcConn != nil {
|
||||
opts = append(opts, option.WithGRPCConn(key.grpcConn))
|
||||
}
|
||||
@@ -266,8 +276,8 @@ func (key *MasterKey) newKMSClient() (*kms.KeyManagementClient, error) {
|
||||
|
||||
// getGoogleCredentials returns the SopsGoogleCredentialsEnv variable, as
|
||||
// either the file contents of the path of a credentials file, or as value in
|
||||
// JSON format. It returns an error if the file cannot be read, and may return
|
||||
// a nil byte slice if no value is set.
|
||||
// JSON format.
|
||||
// It returns an error and a nil byte slice if the file cannot be read.
|
||||
func getGoogleCredentials() ([]byte, error) {
|
||||
if defaultCredentials, ok := os.LookupEnv(SopsGoogleCredentialsEnv); ok && len(defaultCredentials) > 0 {
|
||||
if _, err := os.Stat(defaultCredentials); err == nil {
|
||||
@@ -277,3 +287,16 @@ func getGoogleCredentials() ([]byte, error) {
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// getGoogleOAuthTokenFromEnv returns the SopsGoogleCredentialsOauthTokenEnv variable,
|
||||
// as the OAauth 2.0 token.
|
||||
// It returns an error and a nil byte slice if the envrionment variable is not set.
|
||||
func getGoogleOAuthTokenFromEnv() oauth2.TokenSource {
|
||||
if token, ok := os.LookupEnv(SopsGoogleCredentialsOAuthTokenEnv); ok && len(token) > 0 {
|
||||
tokenSource := oauth2.StaticTokenSource(
|
||||
&oauth2.Token{AccessToken: token},
|
||||
)
|
||||
return tokenSource
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -61,8 +61,9 @@ func TestMasterKey_Encrypt(t *testing.T) {
|
||||
})
|
||||
|
||||
key := MasterKey{
|
||||
grpcConn: newGRPCServer("0"),
|
||||
ResourceID: testResourceID,
|
||||
grpcConn: newGRPCServer("0"),
|
||||
ResourceID: testResourceID,
|
||||
credentialJSON: []byte("arbitrary credentials"),
|
||||
}
|
||||
err := key.Encrypt([]byte("encrypt"))
|
||||
assert.NoError(t, err)
|
||||
@@ -88,9 +89,10 @@ func TestMasterKey_Decrypt(t *testing.T) {
|
||||
Plaintext: []byte(decryptedData),
|
||||
})
|
||||
key := MasterKey{
|
||||
grpcConn: newGRPCServer("0"),
|
||||
ResourceID: testResourceID,
|
||||
EncryptedKey: "encryptedKey",
|
||||
grpcConn: newGRPCServer("0"),
|
||||
ResourceID: testResourceID,
|
||||
EncryptedKey: "encryptedKey",
|
||||
credentialJSON: []byte("arbitrary credentials"),
|
||||
}
|
||||
data, err := key.Decrypt()
|
||||
assert.NoError(t, err)
|
||||
@@ -124,7 +126,7 @@ func TestMasterKey_ToMap(t *testing.T) {
|
||||
}, key.ToMap())
|
||||
}
|
||||
|
||||
func TestMasterKey_createCloudKMSService(t *testing.T) {
|
||||
func TestMasterKey_createCloudKMSService_withCredentialsFile(t *testing.T) {
|
||||
tests := []struct {
|
||||
key MasterKey
|
||||
errString string
|
||||
@@ -144,6 +146,12 @@ func TestMasterKey_createCloudKMSService(t *testing.T) {
|
||||
"type": "authorized_user"}`),
|
||||
},
|
||||
},
|
||||
{
|
||||
key: MasterKey{
|
||||
ResourceID: testResourceID,
|
||||
},
|
||||
errString: `credentials: failed to obtain credentials from "SOPS_GOOGLE_CREDENTIALS"`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
@@ -157,6 +165,29 @@ func TestMasterKey_createCloudKMSService(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestMasterKey_createCloudKMSService_withOauthToken(t *testing.T) {
|
||||
t.Setenv(SopsGoogleCredentialsOAuthTokenEnv, "token")
|
||||
|
||||
masterKey := MasterKey{
|
||||
ResourceID: testResourceID,
|
||||
}
|
||||
|
||||
_, err := masterKey.newKMSClient()
|
||||
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestMasterKey_createCloudKMSService_withoutCredentials(t *testing.T) {
|
||||
masterKey := MasterKey{
|
||||
ResourceID: testResourceID,
|
||||
}
|
||||
|
||||
_, err := masterKey.newKMSClient()
|
||||
|
||||
assert.Error(t, err)
|
||||
assert.ErrorContains(t, err, "credentials: could not find default credentials")
|
||||
}
|
||||
|
||||
func newGRPCServer(port string) *grpc.ClientConn {
|
||||
serv := grpc.NewServer()
|
||||
kmspb.RegisterKeyManagementServiceServer(serv, &mockKeyManagement)
|
||||
|
||||
Reference in New Issue
Block a user