mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-11-01 02:57:59 +00:00
Add support for IAM Auth for Google CloudSQL DBs (#22445)
This commit is contained in:
@@ -12,14 +12,17 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/vault/sdk/database/helper/connutil"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/hashicorp/vault/helper/testhelpers/postgresql"
|
||||
"github.com/hashicorp/vault/sdk/database/dbplugin/v5"
|
||||
dbtesting "github.com/hashicorp/vault/sdk/database/dbplugin/v5/testing"
|
||||
"github.com/hashicorp/vault/sdk/database/helper/dbutil"
|
||||
"github.com/hashicorp/vault/sdk/helper/docker"
|
||||
"github.com/hashicorp/vault/sdk/helper/template"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func getPostgreSQL(t *testing.T, options map[string]interface{}) (*PostgreSQL, func()) {
|
||||
@@ -94,6 +97,93 @@ func TestPostgreSQL_Initialize_ConnURLWithDSNFormat(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// Ensures we can successfully initialize and connect to a CloudSQL database
|
||||
// Requires the following:
|
||||
// - GOOGLE_APPLICATION_CREDENTIALS either JSON or path to file
|
||||
// - CONNECTION_URL to a valid Postgres instance on Google CloudSQL
|
||||
func TestPostgreSQL_Initialize_CloudGCP(t *testing.T) {
|
||||
envConnURL := "CONNECTION_URL"
|
||||
connURL := os.Getenv(envConnURL)
|
||||
if connURL == "" {
|
||||
t.Skipf("env var %s not set, skipping test", envConnURL)
|
||||
}
|
||||
|
||||
credStr := dbtesting.GetGCPTestCredentials(t)
|
||||
|
||||
type testCase struct {
|
||||
req dbplugin.InitializeRequest
|
||||
wantErr bool
|
||||
expectedError string
|
||||
}
|
||||
|
||||
tests := map[string]testCase{
|
||||
"empty auth type": {
|
||||
req: dbplugin.InitializeRequest{
|
||||
Config: map[string]interface{}{
|
||||
"connection_url": connURL,
|
||||
"auth_type": "",
|
||||
},
|
||||
},
|
||||
},
|
||||
"invalid auth type": {
|
||||
req: dbplugin.InitializeRequest{
|
||||
Config: map[string]interface{}{
|
||||
"connection_url": connURL,
|
||||
"auth_type": "invalid",
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
expectedError: "invalid auth_type",
|
||||
},
|
||||
"default credentials": {
|
||||
req: dbplugin.InitializeRequest{
|
||||
Config: map[string]interface{}{
|
||||
"connection_url": connURL,
|
||||
"auth_type": connutil.AuthTypeGCPIAM,
|
||||
},
|
||||
VerifyConnection: true,
|
||||
},
|
||||
},
|
||||
"JSON credentials": {
|
||||
req: dbplugin.InitializeRequest{
|
||||
Config: map[string]interface{}{
|
||||
"connection_url": connURL,
|
||||
"auth_type": connutil.AuthTypeGCPIAM,
|
||||
"service_account_json": credStr,
|
||||
},
|
||||
VerifyConnection: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, test := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
db := new()
|
||||
defer dbtesting.AssertClose(t, db)
|
||||
|
||||
_, err := dbtesting.VerifyInitialize(t, db, test.req)
|
||||
|
||||
if test.wantErr {
|
||||
if err == nil {
|
||||
t.Fatalf("expected error but received nil")
|
||||
}
|
||||
|
||||
if !strings.Contains(err.Error(), test.expectedError) {
|
||||
t.Fatalf("expected error %s, got %s", test.expectedError, err.Error())
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Fatalf("expected no error, received %s", err)
|
||||
}
|
||||
|
||||
if !db.Initialized {
|
||||
t.Fatal("Database should be initialized")
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestPostgreSQL_PasswordAuthentication tests that the default "password_authentication" is "none", and that
|
||||
// an error is returned if an invalid "password_authentication" is provided.
|
||||
func TestPostgreSQL_PasswordAuthentication(t *testing.T) {
|
||||
@@ -1100,6 +1190,86 @@ func TestNewUser_CustomUsername(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewUser_CloudGCP(t *testing.T) {
|
||||
envConnURL := "CONNECTION_URL"
|
||||
connURL := os.Getenv(envConnURL)
|
||||
if connURL == "" {
|
||||
t.Skipf("env var %s not set, skipping test", envConnURL)
|
||||
}
|
||||
|
||||
credStr := dbtesting.GetGCPTestCredentials(t)
|
||||
|
||||
type testCase struct {
|
||||
usernameTemplate string
|
||||
newUserData dbplugin.UsernameMetadata
|
||||
expectedRegex string
|
||||
}
|
||||
|
||||
tests := map[string]testCase{
|
||||
"default template": {
|
||||
usernameTemplate: "",
|
||||
newUserData: dbplugin.UsernameMetadata{
|
||||
DisplayName: "displayname",
|
||||
RoleName: "longrolename",
|
||||
},
|
||||
expectedRegex: "^v-displayn-longrole-[a-zA-Z0-9]{20}-[0-9]{10}$",
|
||||
},
|
||||
"unique template": {
|
||||
usernameTemplate: "foo-bar",
|
||||
newUserData: dbplugin.UsernameMetadata{
|
||||
DisplayName: "displayname",
|
||||
RoleName: "longrolename",
|
||||
},
|
||||
expectedRegex: "^foo-bar$",
|
||||
},
|
||||
}
|
||||
|
||||
for name, test := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
initReq := dbplugin.InitializeRequest{
|
||||
Config: map[string]interface{}{
|
||||
"connection_url": connURL,
|
||||
"username_template": test.usernameTemplate,
|
||||
"auth_type": connutil.AuthTypeGCPIAM,
|
||||
"service_account_json": credStr,
|
||||
},
|
||||
VerifyConnection: true,
|
||||
}
|
||||
|
||||
db := new()
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
||||
defer cancel()
|
||||
|
||||
_, err := db.Initialize(ctx, initReq)
|
||||
require.NoError(t, err)
|
||||
|
||||
newUserReq := dbplugin.NewUserRequest{
|
||||
UsernameConfig: test.newUserData,
|
||||
Statements: dbplugin.Statements{
|
||||
Commands: []string{
|
||||
`
|
||||
CREATE ROLE "{{name}}" WITH
|
||||
LOGIN
|
||||
PASSWORD '{{password}}'
|
||||
VALID UNTIL '{{expiration}}';
|
||||
GRANT SELECT ON ALL TABLES IN SCHEMA public TO "{{name}}";`,
|
||||
},
|
||||
},
|
||||
Password: "myReally-S3curePassword",
|
||||
Expiration: time.Now().Add(1 * time.Hour),
|
||||
}
|
||||
ctx, cancel = context.WithTimeout(context.Background(), 2*time.Second)
|
||||
defer cancel()
|
||||
|
||||
newUserResp, err := db.NewUser(ctx, newUserReq)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Regexp(t, test.expectedRegex, newUserResp.Username)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// This is a long-running integration test which tests the functionality of Postgres's multi-host
|
||||
// connection strings. It uses two Postgres containers preconfigured with Replication Manager
|
||||
// provided by Bitnami. This test currently does not run in CI and must be run manually. This is
|
||||
|
||||
Reference in New Issue
Block a user