feat: add aws rds iam connector

This commit is contained in:
Colin Adler 2024-02-23 22:42:59 +00:00
parent cf4f56dc2f
commit 76374fb187
10 changed files with 309 additions and 70 deletions

View File

@ -65,6 +65,7 @@ import (
"github.com/coder/coder/v2/coderd/autobuild"
"github.com/coder/coder/v2/coderd/batchstats"
"github.com/coder/coder/v2/coderd/database"
"github.com/coder/coder/v2/coderd/database/dbawsiamrds"
"github.com/coder/coder/v2/coderd/database/dbmem"
"github.com/coder/coder/v2/coderd/database/dbmetrics"
"github.com/coder/coder/v2/coderd/database/dbpurge"
@ -669,7 +670,7 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
return xerrors.Errorf("escaping postgres URL: %w", err)
}
sqlDB, err := ConnectToPostgres(ctx, logger, sqlDriver, dbURL)
sqlDB, err := ConnectToPostgres(ctx, logger, sqlDriver, dbURL, codersdk.PostgresAuth(vals.PostgresAuth))
if err != nil {
return xerrors.Errorf("connect to postgres: %w", err)
}
@ -2051,7 +2052,7 @@ func IsLocalhost(host string) bool {
return host == "localhost" || host == "127.0.0.1" || host == "::1"
}
func ConnectToPostgres(ctx context.Context, logger slog.Logger, driver string, dbURL string) (sqlDB *sql.DB, err error) {
func ConnectToPostgres(ctx context.Context, logger slog.Logger, driver string, dbURL string, auth codersdk.PostgresAuth) (sqlDB *sql.DB, err error) {
logger.Debug(ctx, "connecting to postgresql")
// Try to connect for 30 seconds.
@ -2069,11 +2070,25 @@ func ConnectToPostgres(ctx context.Context, logger slog.Logger, driver string, d
logger.Error(ctx, "connect to postgres failed", slog.Error(err))
}()
connect := func() (*sql.DB, error) {
return sql.Open(driver, dbURL)
}
if auth == codersdk.PostgresAuthAWSIAMRDS {
connect = func() (*sql.DB, error) {
connector, err := dbawsiamrds.NewConnector(ctx, dbURL)
if err != nil {
return nil, xerrors.Errorf("create rds iam connector: %w", err)
}
return sql.OpenDB(connector), nil
}
}
var tries int
for r := retry.New(time.Second, 3*time.Second); r.Wait(ctx); {
tries++
sqlDB, err = sql.Open(driver, dbURL)
sqlDB, err = connect()
if err != nil {
logger.Warn(ctx, "connect to postgres: retrying", slog.Error(err), slog.F("try", tries))
continue

View File

@ -25,6 +25,7 @@ import (
func (r *RootCmd) newCreateAdminUserCommand() *clibase.Cmd {
var (
newUserDBURL string
newUserPgAuth string
newUserSSHKeygenAlgorithm string
newUserUsername string
newUserEmail string
@ -62,7 +63,7 @@ func (r *RootCmd) newCreateAdminUserCommand() *clibase.Cmd {
newUserDBURL = url
}
sqlDB, err := ConnectToPostgres(ctx, logger, "postgres", newUserDBURL)
sqlDB, err := ConnectToPostgres(ctx, logger, "postgres", newUserDBURL, codersdk.PostgresAuth(newUserPgAuth))
if err != nil {
return xerrors.Errorf("connect to postgres: %w", err)
}
@ -243,6 +244,14 @@ func (r *RootCmd) newCreateAdminUserCommand() *clibase.Cmd {
Description: "URL of a PostgreSQL database. If empty, the built-in PostgreSQL deployment will be used (Coder must not be already running in this case).",
Value: clibase.StringOf(&newUserDBURL),
},
clibase.Option{
Name: "Postgres Connection Auth",
Description: "Type of auth to use when connecting to postgres.",
Flag: "postgres-connection-auth",
Env: "CODER_PG_CONNECTION_AUTH",
Default: "password",
Value: clibase.EnumOf(&newUserPgAuth, codersdk.PostgresConnectors...),
},
clibase.Option{
Env: "CODER_SSH_KEYGEN_ALGORITHM",
Flag: "ssh-keygen-algorithm",

View File

@ -1764,7 +1764,29 @@ func TestConnectToPostgres(t *testing.T) {
require.NoError(t, err)
t.Cleanup(closeFunc)
sqlDB, err := cli.ConnectToPostgres(ctx, log, "postgres", dbURL)
sqlDB, err := cli.ConnectToPostgres(ctx, log, "postgres", dbURL, codersdk.PostgresAuthPassword)
require.NoError(t, err)
t.Cleanup(func() {
_ = sqlDB.Close()
})
require.NoError(t, sqlDB.PingContext(ctx))
}
func TestConnectToPostgres_AWSIAMRDS(t *testing.T) {
t.Parallel()
// Be sure to set AWS_DEFAULT_REGION to the database region as well.
dbURL := os.Getenv("DBAWSIAMRDS_TEST_URL")
if dbURL == "" {
t.Skip()
}
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitShort)
t.Cleanup(cancel)
log := slogtest.Make(t, nil)
sqlDB, err := cli.ConnectToPostgres(ctx, log, "postgres", dbURL, codersdk.PostgresAuthAWSIAMRDS)
require.NoError(t, err)
t.Cleanup(func() {
_ = sqlDB.Close()

View File

@ -0,0 +1,114 @@
package dbawsiamrds
import (
"context"
"database/sql"
"database/sql/driver"
"fmt"
"net/url"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/feature/rds/auth"
"github.com/jmoiron/sqlx"
"github.com/lib/pq"
"golang.org/x/xerrors"
)
var DriverNotSupportedErr = xerrors.New("driver open method not supported")
var _ driver.Connector = &AwsIamConnector{}
var _ driver.Driver = &AwsIamConnector{}
type AwsIamConnector struct {
cfg aws.Config
dbURL string
}
// NewDB creates a new *sqlx.DB using the aws session from the environment and
// pings postgres to ensure connectivity.
func NewDB(ctx context.Context, dbURL string) (*sqlx.DB, error) {
c, err := NewConnector(ctx, dbURL)
if err != nil {
return nil, xerrors.Errorf("creating connector: %w", err)
}
sqlDB := sql.OpenDB(c)
sqlxDB := sqlx.NewDb(sqlDB, "postgres")
err = sqlxDB.PingContext(ctx)
if err != nil {
return nil, xerrors.Errorf("ping postgres: %w", err)
}
return sqlxDB, nil
}
// NewConnector creates a new `AwsIamConnector` using the aws session from the
// environment.
func NewConnector(ctx context.Context, dbURL string) (*AwsIamConnector, error) {
cfg, err := config.LoadDefaultConfig(ctx)
if err != nil {
return nil, err
}
c := &AwsIamConnector{
cfg: cfg,
dbURL: dbURL,
}
return c, nil
}
// Connect fulfills the driver.Connector interface using aws iam rds credentials
// from the environment
func (c *AwsIamConnector) Connect(ctx context.Context) (driver.Conn, error) {
nURL, err := getAuthenticatedURL(c.cfg, c.dbURL)
if err != nil {
return nil, xerrors.Errorf("assigning authentication token to url: %w", err)
}
connector, err := pq.NewConnector(nURL)
if err != nil {
return nil, xerrors.Errorf("building new pq connector: %w", err)
}
conn, err := connector.Connect(ctx)
if err != nil {
return nil, xerrors.Errorf("making connection: %w", err)
}
return conn, nil
}
// Driver fulfills the driver.Connector interface. It shouldn't be used
func (c *AwsIamConnector) Driver() driver.Driver {
return c
}
// Open fulfills the driver.Driver interface with an error.
// This interface should not be opened via the driver open method.
func (*AwsIamConnector) Open(_ string) (driver.Conn, error) {
return nil, DriverNotSupportedErr
}
// getAuthenticatedURL generates an RDS auth token and inserts it into the
// password field of the supplied URL.
func getAuthenticatedURL(cfg aws.Config, dbURL string) (string, error) {
nURL, err := url.Parse(dbURL)
if err != nil {
return "", xerrors.Errorf("parsing dbURL: %w", err)
}
// generate a new rds session auth tokenized URL
rdsEndpoint := fmt.Sprintf("%s:%s", nURL.Hostname(), nURL.Port())
token, err := auth.BuildAuthToken(context.Background(), rdsEndpoint, cfg.Region, nURL.User.Username(), cfg.Credentials)
if err != nil {
return "", xerrors.Errorf("building rds auth token: %w", err)
}
// set token as user password
nURL.User = url.UserPassword(nURL.User.Username(), token)
return nURL.String(), nil
}

View File

@ -0,0 +1,33 @@
package dbawsiamrds_test
import (
"context"
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/coder/coder/v2/coderd/database/dbawsiamrds"
"github.com/coder/coder/v2/testutil"
)
func TestConnector(t *testing.T) {
t.Parallel()
// Be sure to set AWS_DEFAULT_REGION to the database region as well.
url := os.Getenv("DBAWSIAMRDS_TEST_URL")
if url == "" {
t.Skip()
}
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitShort)
defer cancel()
db, err := dbawsiamrds.NewDB(ctx, url)
require.NoError(t, err)
var i int
err = db.GetContext(ctx, &i, "select 1;")
require.NoError(t, err)
assert.Equal(t, 1, i)
}

View File

@ -29,8 +29,7 @@ const maxRetries = 5
// fail. Let's say the transaction that sets A=2 succeeds. Then the first B=2
// transaction fails, but here we retry. The second attempt we read A=2, B=1,
// then write A=2, B=2 as desired, and this succeeds.
func ReadModifyUpdate(db Store, f func(tx Store) error,
) error {
func ReadModifyUpdate(db Store, f func(tx Store) error) error {
var err error
for retries := 0; retries < maxRetries; retries++ {
err = db.InTx(f, &sql.TxOptions{

View File

@ -133,6 +133,18 @@ func (c *Client) Entitlements(ctx context.Context) (Entitlements, error) {
return ent, json.NewDecoder(res.Body).Decode(&ent)
}
type PostgresAuth string
const (
PostgresAuthPassword PostgresAuth = "password"
PostgresAuthAWSIAMRDS PostgresAuth = "awsiamrds"
)
var PostgresConnectors = []string{
string(PostgresAuthPassword),
string(PostgresAuthAWSIAMRDS),
}
// DeploymentValues is the central configuration values the coder server.
type DeploymentValues struct {
Verbose clibase.Bool `json:"verbose,omitempty"`
@ -152,6 +164,7 @@ type DeploymentValues struct {
CacheDir clibase.String `json:"cache_directory,omitempty" typescript:",notnull"`
InMemoryDatabase clibase.Bool `json:"in_memory_database,omitempty" typescript:",notnull"`
PostgresURL clibase.String `json:"pg_connection_url,omitempty" typescript:",notnull"`
PostgresAuth string `json:"pg_auth,omitempty" typescript:",notnull"`
OAuth2 OAuth2Config `json:"oauth2,omitempty" typescript:",notnull"`
OIDC OIDCConfig `json:"oidc,omitempty" typescript:",notnull"`
Telemetry TelemetryConfig `json:"telemetry,omitempty" typescript:",notnull"`
@ -1610,6 +1623,16 @@ when required by your organization's security policy.`,
Env: "CODER_PG_CONNECTION_URL",
Annotations: clibase.Annotations{}.Mark(annotationSecretKey, "true"),
Value: &c.PostgresURL,
YAML: "pgConnectionURL",
},
{
Name: "Postgres Auth",
Description: "Type of auth to use when connecting to postgres.",
Flag: "postgres-auth",
Env: "CODER_PG_AUTH",
Default: "password",
Value: clibase.EnumOf(&c.PostgresAuth, PostgresConnectors...),
YAML: "pgAuth",
},
{
Name: "Secure Auth Cookie",

View File

@ -13,6 +13,7 @@ import (
"github.com/coder/coder/v2/cli"
"github.com/coder/coder/v2/cli/clibase"
"github.com/coder/coder/v2/cli/cliui"
"github.com/coder/coder/v2/codersdk"
"github.com/coder/coder/v2/enterprise/dbcrypt"
"golang.org/x/xerrors"
@ -88,7 +89,7 @@ func (*RootCmd) dbcryptRotateCmd() *clibase.Cmd {
return err
}
sqlDB, err := cli.ConnectToPostgres(inv.Context(), logger, "postgres", flags.PostgresURL)
sqlDB, err := cli.ConnectToPostgres(inv.Context(), logger, "postgres", flags.PostgresURL, codersdk.PostgresAuth(flags.PostgresAuth))
if err != nil {
return xerrors.Errorf("connect to postgres: %w", err)
}
@ -145,7 +146,7 @@ func (*RootCmd) dbcryptDecryptCmd() *clibase.Cmd {
return err
}
sqlDB, err := cli.ConnectToPostgres(inv.Context(), logger, "postgres", flags.PostgresURL)
sqlDB, err := cli.ConnectToPostgres(inv.Context(), logger, "postgres", flags.PostgresURL, codersdk.PostgresAuth(flags.PostgresAuth))
if err != nil {
return xerrors.Errorf("connect to postgres: %w", err)
}
@ -192,7 +193,7 @@ Are you sure you want to continue?`
return err
}
sqlDB, err := cli.ConnectToPostgres(inv.Context(), logger, "postgres", flags.PostgresURL)
sqlDB, err := cli.ConnectToPostgres(inv.Context(), logger, "postgres", flags.PostgresURL, codersdk.PostgresAuth(flags.PostgresAuth))
if err != nil {
return xerrors.Errorf("connect to postgres: %w", err)
}
@ -212,9 +213,10 @@ Are you sure you want to continue?`
}
type rotateFlags struct {
PostgresURL string
New string
Old []string
PostgresURL string
PostgresAuth string
New string
Old []string
}
func (f *rotateFlags) attach(opts *clibase.OptionSet) {
@ -226,6 +228,14 @@ func (f *rotateFlags) attach(opts *clibase.OptionSet) {
Description: "The connection URL for the Postgres database.",
Value: clibase.StringOf(&f.PostgresURL),
},
clibase.Option{
Name: "Postgres Connection Auth",
Description: "Type of auth to use when connecting to postgres.",
Flag: "postgres-connection-auth",
Env: "CODER_PG_CONNECTION_AUTH",
Default: "password",
Value: clibase.EnumOf(&f.PostgresAuth, codersdk.PostgresConnectors...),
},
clibase.Option{
Flag: "new-key",
Env: "CODER_EXTERNAL_TOKEN_ENCRYPTION_ENCRYPT_NEW_KEY",
@ -274,8 +284,9 @@ func (f *rotateFlags) valid() error {
}
type decryptFlags struct {
PostgresURL string
Keys []string
PostgresURL string
PostgresAuth string
Keys []string
}
func (f *decryptFlags) attach(opts *clibase.OptionSet) {
@ -287,6 +298,14 @@ func (f *decryptFlags) attach(opts *clibase.OptionSet) {
Description: "The connection URL for the Postgres database.",
Value: clibase.StringOf(&f.PostgresURL),
},
clibase.Option{
Name: "Postgres Connection Auth",
Description: "Type of auth to use when connecting to postgres.",
Flag: "postgres-connection-auth",
Env: "CODER_PG_CONNECTION_AUTH",
Default: "password",
Value: clibase.EnumOf(&f.PostgresAuth, codersdk.PostgresConnectors...),
},
clibase.Option{
Flag: "keys",
Env: "CODER_EXTERNAL_TOKEN_ENCRYPTION_DECRYPT_KEYS",
@ -318,8 +337,9 @@ func (f *decryptFlags) valid() error {
}
type deleteFlags struct {
PostgresURL string
Confirm bool
PostgresURL string
PostgresAuth string
Confirm bool
}
func (f *deleteFlags) attach(opts *clibase.OptionSet) {
@ -331,6 +351,14 @@ func (f *deleteFlags) attach(opts *clibase.OptionSet) {
Description: "The connection URL for the Postgres database.",
Value: clibase.StringOf(&f.PostgresURL),
},
clibase.Option{
Name: "Postgres Connection Auth",
Description: "Type of auth to use when connecting to postgres.",
Flag: "postgres-connection-auth",
Env: "CODER_PG_CONNECTION_AUTH",
Default: "password",
Value: clibase.EnumOf(&f.PostgresAuth, codersdk.PostgresConnectors...),
},
cliui.SkipPromptOption(),
)
}

48
go.mod
View File

@ -82,7 +82,9 @@ require (
github.com/andybalholm/brotli v1.1.0
github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2
github.com/awalterschulze/gographviz v2.0.3+incompatible
github.com/aws/smithy-go v1.20.0
github.com/aws/aws-sdk-go-v2/feature/rds/auth v1.4.3
github.com/aws/smithy-go v1.20.1
github.com/benbjohnson/clock v1.3.5
github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816
github.com/bramvdbogaerde/go-scp v1.3.0
github.com/briandowns/spinner v1.18.1
@ -123,6 +125,7 @@ require (
github.com/gohugoio/hugo v0.123.3
github.com/golang-jwt/jwt/v4 v4.5.0
github.com/golang-migrate/migrate/v4 v4.17.0
github.com/gomarkdown/markdown v0.0.0-20231222211730-1d6d20845b47
github.com/google/go-cmp v0.6.0
github.com/google/go-github/v43 v43.0.1-0.20220414155304-00e42332e405
github.com/google/uuid v1.6.0
@ -130,6 +133,7 @@ require (
github.com/hashicorp/go-reap v0.0.0-20170704170343-bf58d8a43e7b
github.com/hashicorp/go-version v1.6.0
github.com/hashicorp/hc-install v0.6.3
github.com/hashicorp/hcl/v2 v2.20.0
github.com/hashicorp/terraform-config-inspect v0.0.0-20211115214459-90acf1ca460f
github.com/hashicorp/terraform-json v0.21.0
github.com/hashicorp/yamux v0.1.1
@ -170,6 +174,7 @@ require (
github.com/unrolled/secure v1.14.0
github.com/valyala/fasthttp v1.52.0
github.com/wagslane/go-password-validator v0.3.0
github.com/zclconf/go-cty v1.14.1
go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1
go.nhat.io/otelsql v0.12.0
go.opentelemetry.io/otel v1.19.0
@ -179,6 +184,7 @@ require (
go.opentelemetry.io/otel/trace v1.19.0
go.uber.org/atomic v1.11.0
go.uber.org/goleak v1.2.1
go.uber.org/mock v0.4.0
go4.org/netipx v0.0.0-20230728180743-ad4cb58a6516
golang.org/x/crypto v0.20.0
golang.org/x/exp v0.0.0-20231219180239-dc181d75b848
@ -204,19 +210,6 @@ require (
tailscale.com v1.46.1
)
require go.uber.org/mock v0.4.0
require (
github.com/benbjohnson/clock v1.3.5
github.com/gomarkdown/markdown v0.0.0-20231222211730-1d6d20845b47
)
require (
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 // indirect
github.com/mitchellh/hashstructure v1.1.0 // indirect
github.com/tdewolff/test v1.0.11-0.20240106005702-7de5f7df4739 // indirect
)
require (
cloud.google.com/go/compute v1.23.3 // indirect
cloud.google.com/go/logging v1.9.0 // indirect
@ -244,18 +237,19 @@ require (
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
github.com/armon/go-radix v1.0.1-0.20221118154546-54df44f2176c // indirect
github.com/aws/aws-sdk-go-v2 v1.24.1 // indirect
github.com/aws/aws-sdk-go-v2/config v1.26.1 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.16.12 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.10 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.9 // indirect
github.com/aws/aws-sdk-go-v2 v1.25.3
github.com/aws/aws-sdk-go-v2/config v1.27.7
github.com/aws/aws-sdk-go-v2/credentials v1.17.7 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.15.3 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.3 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.3 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.1 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.5 // indirect
github.com/aws/aws-sdk-go-v2/service/ssm v1.44.5 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.18.5 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.5 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.26.5 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.20.2 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.2 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.28.4 // indirect
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/aymerick/douceur v0.2.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
@ -321,7 +315,6 @@ require (
github.com/hashicorp/go-hclog v1.5.0 // indirect
github.com/hashicorp/go-uuid v1.0.3 // indirect
github.com/hashicorp/hcl v1.0.1-vault-5 // indirect
github.com/hashicorp/hcl/v2 v2.20.0
github.com/hashicorp/logutils v1.0.0 // indirect
github.com/hashicorp/terraform-plugin-go v0.12.0 // indirect
github.com/hashicorp/terraform-plugin-log v0.7.0 // indirect
@ -353,6 +346,7 @@ require (
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/go-ps v1.0.0 // indirect
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
github.com/mitchellh/hashstructure v1.1.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/moby/term v0.5.0 // indirect
github.com/muesli/reflow v0.3.0 // indirect
@ -389,6 +383,7 @@ require (
github.com/tchap/go-patricia/v2 v2.3.1 // indirect
github.com/tcnksm/go-httpstat v0.2.0 // indirect
github.com/tdewolff/parse/v2 v2.7.12 // indirect
github.com/tdewolff/test v1.0.11-0.20240106005702-7de5f7df4739 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
github.com/tinylib/msgp v1.1.8 // indirect
@ -407,7 +402,6 @@ require (
github.com/yashtewari/glob-intersection v0.2.0 // indirect
github.com/yuin/goldmark v1.7.0 // indirect
github.com/yuin/goldmark-emoji v1.0.2 // indirect
github.com/zclconf/go-cty v1.14.1
github.com/zeebo/errs v1.3.0 // indirect
go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/contrib v1.19.0 // indirect

54
go.sum
View File

@ -92,34 +92,36 @@ github.com/armon/go-radix v1.0.1-0.20221118154546-54df44f2176c h1:651/eoCRnQ7YtS
github.com/armon/go-radix v1.0.1-0.20221118154546-54df44f2176c/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/awalterschulze/gographviz v2.0.3+incompatible h1:9sVEXJBJLwGX7EQVhLm2elIKCm7P2YHFC8v6096G09E=
github.com/awalterschulze/gographviz v2.0.3+incompatible/go.mod h1:GEV5wmg4YquNw7v1kkyoX9etIk8yVmXj+AkDHuuETHs=
github.com/aws/aws-sdk-go-v2 v1.24.1 h1:xAojnj+ktS95YZlDf0zxWBkbFtymPeDP+rvUQIH3uAU=
github.com/aws/aws-sdk-go-v2 v1.24.1/go.mod h1:LNh45Br1YAkEKaAqvmE1m8FUx6a5b/V0oAKV7of29b4=
github.com/aws/aws-sdk-go-v2/config v1.26.1 h1:z6DqMxclFGL3Zfo+4Q0rLnAZ6yVkzCRxhRMsiRQnD1o=
github.com/aws/aws-sdk-go-v2/config v1.26.1/go.mod h1:ZB+CuKHRbb5v5F0oJtGdhFTelmrxd4iWO1lf0rQwSAg=
github.com/aws/aws-sdk-go-v2/credentials v1.16.12 h1:v/WgB8NxprNvr5inKIiVVrXPuuTegM+K8nncFkr1usU=
github.com/aws/aws-sdk-go-v2/credentials v1.16.12/go.mod h1:X21k0FjEJe+/pauud82HYiQbEr9jRKY3kXEIQ4hXeTQ=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.10 h1:w98BT5w+ao1/r5sUuiH6JkVzjowOKeOJRHERyy1vh58=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.10/go.mod h1:K2WGI7vUvkIv1HoNbfBA1bvIZ+9kL3YVmWxeKuLQsiw=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10 h1:vF+Zgd9s+H4vOXd5BMaPWykta2a6Ih0AKLq/X6NYKn4=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10/go.mod h1:6BkRjejp/GR4411UGqkX8+wFMbFbqsUIimfK4XjOKR4=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10 h1:nYPe006ktcqUji8S2mqXf9c/7NdiKriOwMvWQHgYztw=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10/go.mod h1:6UV4SZkVvmODfXKql4LCbaZUpF7HO2BX38FgBf9ZOLw=
github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2 h1:GrSw8s0Gs/5zZ0SX+gX4zQjRnRsMJDJ2sLur1gRBhEM=
github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2/go.mod h1:6fQQgfuGmw8Al/3M2IgIllycxV7ZW7WCdVSqfBeUiCY=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 h1:/b31bi3YVNlkzkBrm9LfpaKoaYZUxIAj4sHfOTmLfqw=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4/go.mod h1:2aGXHFmbInwgP9ZfpmdIfOELL79zhdNYNmReK8qDfdQ=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.9 h1:Nf2sHxjMJR8CSImIVCONRi4g0Su3J+TSTbS7G0pUeMU=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.9/go.mod h1:idky4TER38YIjr2cADF1/ugFMKvZV7p//pVeV5LZbF0=
github.com/aws/aws-sdk-go-v2 v1.25.3 h1:xYiLpZTQs1mzvz5PaI6uR0Wh57ippuEthxS4iK5v0n0=
github.com/aws/aws-sdk-go-v2 v1.25.3/go.mod h1:35hUlJVYd+M++iLI3ALmVwMOyRYMmRqUXpTtRGW+K9I=
github.com/aws/aws-sdk-go-v2/config v1.27.7 h1:JSfb5nOQF01iOgxFI5OIKWwDiEXWTyTgg1Mm1mHi0A4=
github.com/aws/aws-sdk-go-v2/config v1.27.7/go.mod h1:PH0/cNpoMO+B04qET699o5W92Ca79fVtbUnvMIZro4I=
github.com/aws/aws-sdk-go-v2/credentials v1.17.7 h1:WJd+ubWKoBeRh7A5iNMnxEOs982SyVKOJD+K8HIezu4=
github.com/aws/aws-sdk-go-v2/credentials v1.17.7/go.mod h1:UQi7LMR0Vhvs+44w5ec8Q+VS+cd10cjwgHwiVkE0YGU=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.15.3 h1:p+y7FvkK2dxS+FEwRIDHDe//ZX+jDhP8HHE50ppj4iI=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.15.3/go.mod h1:/fYB+FZbDlwlAiynK9KDXlzZl3ANI9JkD0Uhz5FjNT4=
github.com/aws/aws-sdk-go-v2/feature/rds/auth v1.4.3 h1:mfxA6HX/mla8BrjVHdVD0G49+0Z+xKel//NCPBk0qbo=
github.com/aws/aws-sdk-go-v2/feature/rds/auth v1.4.3/go.mod h1:PjvlBlYNNXPrMAGarXrnV+UYv1T9XyTT2Ono41NQjq8=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.3 h1:ifbIbHZyGl1alsAhPIYsHOg5MuApgqOvVeI8wIugXfs=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.3/go.mod h1:oQZXg3c6SNeY6OZrDY+xHcF4VGIEoNotX2B4PrDeoJI=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.3 h1:Qvodo9gHG9F3E8SfYOspPeBt0bjSbsevK8WhRAUHcoY=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.3/go.mod h1:vCKrdLXtybdf/uQd/YfVR2r5pcbNuEYKzMQpcxmeSJw=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.1 h1:EyBZibRTVAs6ECHZOw5/wlylS9OcTzwyjeQMudmREjE=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.1/go.mod h1:JKpmtYhhPs7D97NL/ltqz7yCkERFW5dOlHyVl66ZYF8=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.5 h1:K/NXvIftOlX+oGgWGIa3jDyYLDNsdVhsjHmsBH2GLAQ=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.5/go.mod h1:cl9HGLV66EnCmMNzq4sYOti+/xo8w34CsgzVtm2GgsY=
github.com/aws/aws-sdk-go-v2/service/ssm v1.44.5 h1:5SI5O2tMp/7E/FqhYnaKdxbWjlCi2yujjNI/UO725iU=
github.com/aws/aws-sdk-go-v2/service/ssm v1.44.5/go.mod h1:uXndCJoDO9gpuK24rNWVCnrGNUydKFEAYAZ7UU9S0rQ=
github.com/aws/aws-sdk-go-v2/service/sso v1.18.5 h1:ldSFWz9tEHAwHNmjx2Cvy1MjP5/L9kNoR0skc6wyOOM=
github.com/aws/aws-sdk-go-v2/service/sso v1.18.5/go.mod h1:CaFfXLYL376jgbP7VKC96uFcU8Rlavak0UlAwk1Dlhc=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.5 h1:2k9KmFawS63euAkY4/ixVNsYYwrwnd5fIvgEKkfZFNM=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.5/go.mod h1:W+nd4wWDVkSUIox9bacmkBP5NMFQeTJ/xqNabpzSR38=
github.com/aws/aws-sdk-go-v2/service/sts v1.26.5 h1:5UYvv8JUvllZsRnfrcMQ+hJ9jNICmcgKPAO1CER25Wg=
github.com/aws/aws-sdk-go-v2/service/sts v1.26.5/go.mod h1:XX5gh4CB7wAs4KhcF46G6C8a2i7eupU19dcAAE+EydU=
github.com/aws/smithy-go v1.20.0 h1:6+kZsCXZwKxZS9RfISnPc4EXlHoyAkm2hPuM8X2BrrQ=
github.com/aws/smithy-go v1.20.0/go.mod h1:uo5RKksAl4PzhqaAbjd4rLgFoq5koTsQKYuGe7dklGc=
github.com/aws/aws-sdk-go-v2/service/sso v1.20.2 h1:XOPfar83RIRPEzfihnp+U6udOveKZJvPQ76SKWrLRHc=
github.com/aws/aws-sdk-go-v2/service/sso v1.20.2/go.mod h1:Vv9Xyk1KMHXrR3vNQe8W5LMFdTjSeWk0gBZBzvf3Qa0=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.2 h1:pi0Skl6mNl2w8qWZXcdOyg197Zsf4G97U7Sso9JXGZE=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.2/go.mod h1:JYzLoEVeLXk+L4tn1+rrkfhkxl6mLDEVaDSvGq9og90=
github.com/aws/aws-sdk-go-v2/service/sts v1.28.4 h1:Ppup1nVNAOWbBOrcoOxaxPeEnSFB2RnnQdguhXpmeQk=
github.com/aws/aws-sdk-go-v2/service/sts v1.28.4/go.mod h1:+K1rNPVyGxkRuv9NNiaZ4YhBFuyw2MMA9SlIJ1Zlpz8=
github.com/aws/smithy-go v1.20.1 h1:4SZlSlMr36UEqC7XOyRVb27XMeZubNcBNN+9IgEPIQw=
github.com/aws/smithy-go v1.20.1/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E=
github.com/aymanbagabas/go-osc52 v1.0.3/go.mod h1:zT8H+Rk4VSabYN90pWyugflM3ZhpTZNC7cASDfUCdT4=
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=