Skip to content

Commit c171596

Browse files
IAM RDS cross account role support #14
2 parents 6437ece + e7006f0 commit c171596

File tree

3 files changed

+86
-37
lines changed

3 files changed

+86
-37
lines changed

go.mod

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
module github.com/corbaltcode/go-libraries
22

3-
go 1.22
3+
go 1.24
44

55
require (
6-
github.com/aws/aws-sdk-go-v2 v1.38.0
6+
github.com/aws/aws-sdk-go-v2 v1.41.0
77
github.com/aws/aws-sdk-go-v2/config v1.31.0
8+
github.com/aws/aws-sdk-go-v2/credentials v1.19.5
9+
github.com/aws/aws-sdk-go-v2/feature/rds/auth v1.6.16
810
github.com/aws/aws-sdk-go-v2/service/ssm v1.63.0
11+
github.com/aws/aws-sdk-go-v2/service/sts v1.41.5
912
github.com/coreos/go-oidc/v3 v3.6.0
1013
github.com/google/go-cmp v0.5.9
1114
github.com/jmoiron/sqlx v1.3.5
@@ -14,17 +17,15 @@ require (
1417
)
1518

1619
require (
17-
github.com/aws/aws-sdk-go-v2/credentials v1.18.4 // indirect
18-
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.3 // indirect
19-
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.3 // indirect
20-
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.3 // indirect
20+
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.16 // indirect
21+
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16 // indirect
22+
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16 // indirect
2123
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect
22-
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.0 // indirect
23-
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.3 // indirect
24-
github.com/aws/aws-sdk-go-v2/service/sso v1.28.0 // indirect
25-
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.33.0 // indirect
26-
github.com/aws/aws-sdk-go-v2/service/sts v1.37.0 // indirect
27-
github.com/aws/smithy-go v1.22.5 // indirect
24+
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 // indirect
25+
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.16 // indirect
26+
github.com/aws/aws-sdk-go-v2/service/sso v1.30.7 // indirect
27+
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.12 // indirect
28+
github.com/aws/smithy-go v1.24.0 // indirect
2829
github.com/dustin/go-humanize v1.0.1 // indirect
2930
github.com/go-jose/go-jose/v3 v3.0.0 // indirect
3031
github.com/golang/protobuf v1.5.2 // indirect

go.sum

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,33 @@
1-
github.com/aws/aws-sdk-go-v2 v1.38.0 h1:UCRQ5mlqcFk9HJDIqENSLR3wiG1VTWlyUfLDEvY7RxU=
2-
github.com/aws/aws-sdk-go-v2 v1.38.0/go.mod h1:9Q0OoGQoboYIAJyslFyF1f5K1Ryddop8gqMhWx/n4Wg=
1+
github.com/aws/aws-sdk-go-v2 v1.41.0 h1:tNvqh1s+v0vFYdA1xq0aOJH+Y5cRyZ5upu6roPgPKd4=
2+
github.com/aws/aws-sdk-go-v2 v1.41.0/go.mod h1:MayyLB8y+buD9hZqkCW3kX1AKq07Y5pXxtgB+rRFhz0=
33
github.com/aws/aws-sdk-go-v2/config v1.31.0 h1:9yH0xiY5fUnVNLRWO0AtayqwU1ndriZdN78LlhruJR4=
44
github.com/aws/aws-sdk-go-v2/config v1.31.0/go.mod h1:VeV3K72nXnhbe4EuxxhzsDc/ByrCSlZwUnWH52Nde/I=
5-
github.com/aws/aws-sdk-go-v2/credentials v1.18.4 h1:IPd0Algf1b+Qy9BcDp0sCUcIWdCQPSzDoMK3a8pcbUM=
6-
github.com/aws/aws-sdk-go-v2/credentials v1.18.4/go.mod h1:nwg78FjH2qvsRM1EVZlX9WuGUJOL5od+0qvm0adEzHk=
7-
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.3 h1:GicIdnekoJsjq9wqnvyi2elW6CGMSYKhdozE7/Svh78=
8-
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.3/go.mod h1:R7BIi6WNC5mc1kfRM7XM/VHC3uRWkjc396sfabq4iOo=
9-
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.3 h1:o9RnO+YZ4X+kt5Z7Nvcishlz0nksIt2PIzDglLMP0vA=
10-
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.3/go.mod h1:+6aLJzOG1fvMOyzIySYjOFjcguGvVRL68R+uoRencN4=
11-
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.3 h1:joyyUFhiTQQmVK6ImzNU9TQSNRNeD9kOklqTzyk5v6s=
12-
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.3/go.mod h1:+vNIyZQP3b3B1tSLI0lxvrU9cfM7gpdRXMFfm67ZcPc=
5+
github.com/aws/aws-sdk-go-v2/credentials v1.19.5 h1:xMo63RlqP3ZZydpJDMBsH9uJ10hgHYfQFIk1cHDXrR4=
6+
github.com/aws/aws-sdk-go-v2/credentials v1.19.5/go.mod h1:hhbH6oRcou+LpXfA/0vPElh/e0M3aFeOblE1sssAAEk=
7+
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.16 h1:80+uETIWS1BqjnN9uJ0dBUaETh+P1XwFy5vwHwK5r9k=
8+
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.16/go.mod h1:wOOsYuxYuB/7FlnVtzeBYRcjSRtQpAW0hCP7tIULMwo=
9+
github.com/aws/aws-sdk-go-v2/feature/rds/auth v1.6.16 h1:LFB4eCU2S9wpFAkEnSqtP8CgdOk0cjMIzuXas1+rbWM=
10+
github.com/aws/aws-sdk-go-v2/feature/rds/auth v1.6.16/go.mod h1:Q7hjCcQzFZ9QgZ+xeJhO4X1rv7uKAl4aoBEjab6MS8k=
11+
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16 h1:rgGwPzb82iBYSvHMHXc8h9mRoOUBZIGFgKb9qniaZZc=
12+
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16/go.mod h1:L/UxsGeKpGoIj6DxfhOWHWQ/kGKcd4I1VncE4++IyKA=
13+
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16 h1:1jtGzuV7c82xnqOVfx2F0xmJcOw5374L7N6juGW6x6U=
14+
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16/go.mod h1:M2E5OQf+XLe+SZGmmpaI2yy+J326aFf6/+54PoxSANc=
1315
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo=
1416
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo=
15-
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.0 h1:6+lZi2JeGKtCraAj1rpoZfKqnQ9SptseRZioejfUOLM=
16-
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.0/go.mod h1:eb3gfbVIxIoGgJsi9pGne19dhCBpK6opTYpQqAmdy44=
17-
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.3 h1:ieRzyHXypu5ByllM7Sp4hC5f/1Fy5wqxqY0yB85hC7s=
18-
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.3/go.mod h1:O5ROz8jHiOAKAwx179v+7sHMhfobFVi6nZt8DEyiYoM=
17+
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 h1:0ryTNEdJbzUCEWkVXEXoqlXV72J5keC1GvILMOuD00E=
18+
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4/go.mod h1:HQ4qwNZh32C3CBeO6iJLQlgtMzqeG17ziAA/3KDJFow=
19+
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.16 h1:oHjJHeUy0ImIV0bsrX0X91GkV5nJAyv1l1CC9lnO0TI=
20+
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.16/go.mod h1:iRSNGgOYmiYwSCXxXaKb9HfOEj40+oTKn8pTxMlYkRM=
1921
github.com/aws/aws-sdk-go-v2/service/ssm v1.63.0 h1:1T8wFNEtOP4lgLC7v8Fzgbb4kFrMmnscG7kOqkbA26c=
2022
github.com/aws/aws-sdk-go-v2/service/ssm v1.63.0/go.mod h1:CDVmu8K5JKdgdJakdZ9gC3K6OJ/+izv/kUncFeGRIj4=
21-
github.com/aws/aws-sdk-go-v2/service/sso v1.28.0 h1:Mc/MKBf2m4VynyJkABoVEN+QzkfLqGj0aiJuEe7cMeM=
22-
github.com/aws/aws-sdk-go-v2/service/sso v1.28.0/go.mod h1:iS5OmxEcN4QIPXARGhavH7S8kETNL11kym6jhoS7IUQ=
23-
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.33.0 h1:6csaS/aJmqZQbKhi1EyEMM7yBW653Wy/B9hnBofW+sw=
24-
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.33.0/go.mod h1:59qHWaY5B+Rs7HGTuVGaC32m0rdpQ68N8QCN3khYiqs=
25-
github.com/aws/aws-sdk-go-v2/service/sts v1.37.0 h1:MG9VFW43M4A8BYeAfaJJZWrroinxeTi2r3+SnmLQfSA=
26-
github.com/aws/aws-sdk-go-v2/service/sts v1.37.0/go.mod h1:JdeBDPgpJfuS6rU/hNglmOigKhyEZtBmbraLE4GK1J8=
27-
github.com/aws/smithy-go v1.22.5 h1:P9ATCXPMb2mPjYBgueqJNCA5S9UfktsW0tTxi+a7eqw=
28-
github.com/aws/smithy-go v1.22.5/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI=
23+
github.com/aws/aws-sdk-go-v2/service/sso v1.30.7 h1:eYnlt6QxnFINKzwxP5/Ucs1vkG7VT3Iezmvfgc2waUw=
24+
github.com/aws/aws-sdk-go-v2/service/sso v1.30.7/go.mod h1:+fWt2UHSb4kS7Pu8y+BMBvJF0EWx+4H0hzNwtDNRTrg=
25+
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.12 h1:AHDr0DaHIAo8c9t1emrzAlVDFp+iMMKnPdYy6XO4MCE=
26+
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.12/go.mod h1:GQ73XawFFiWxyWXMHWfhiomvP3tXtdNar/fi8z18sx0=
27+
github.com/aws/aws-sdk-go-v2/service/sts v1.41.5 h1:SciGFVNZ4mHdm7gpD1dgZYnCuVdX1s+lFTg4+4DOy70=
28+
github.com/aws/aws-sdk-go-v2/service/sts v1.41.5/go.mod h1:iW40X4QBmUxdP+fZNOpfmkdMZqsovezbAeO+Ubiv2pk=
29+
github.com/aws/smithy-go v1.24.0 h1:LpilSUItNPFr1eY85RYgTIg5eIEPtvFbskaFcmmIUnk=
30+
github.com/aws/smithy-go v1.24.0/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0=
2931
github.com/coreos/go-oidc/v3 v3.6.0 h1:AKVxfYw1Gmkn/w96z0DbT/B/xFnzTd3MkZvWLjF4n/o=
3032
github.com/coreos/go-oidc/v3 v3.6.0/go.mod h1:ZpHUsHBucTUj6WOkrP4E20UPynbLZzhTQ1XKCXkxyPc=
3133
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=

pgutils/connector.go

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,16 @@ import (
66
"fmt"
77
"log"
88
"net/url"
9+
"time"
910

1011
"database/sql"
1112
"database/sql/driver"
1213

1314
"github.com/aws/aws-sdk-go-v2/aws"
1415
awsconfig "github.com/aws/aws-sdk-go-v2/config"
16+
"github.com/aws/aws-sdk-go-v2/credentials/stscreds"
1517
"github.com/aws/aws-sdk-go-v2/feature/rds/auth"
18+
"github.com/aws/aws-sdk-go-v2/service/sts"
1619
"github.com/jmoiron/sqlx"
1720
"github.com/lib/pq"
1821
)
@@ -91,6 +94,20 @@ type IAMAuthConfig struct {
9194
RDSEndpoint string
9295
User string
9396
Database string
97+
98+
// Optional: cross-account role assumption.
99+
// Set this to a role ARN in the RDS account (Account A) that has rds-db:connect.
100+
AssumeRoleARN string
101+
102+
// Optional: if your trust policy requires an external ID.
103+
AssumeRoleExternalID string
104+
105+
// Optional: override the default session name.
106+
AssumeRoleSessionName string
107+
108+
// Optional: override STS assume role duration.
109+
// If zero, SDK default is used.
110+
AssumeRoleDuration time.Duration
94111
}
95112

96113
type iamAuthConnectionStringProvider struct {
@@ -105,7 +122,7 @@ func (p *iamAuthConnectionStringProvider) getBaseConnectionString(ctx context.Co
105122
if err != nil {
106123
return "", fmt.Errorf("building auth token: %w", err)
107124
}
108-
log.Printf("Signing RDS IAM token for user: %s", p.User)
125+
log.Printf("Signing RDS IAM token for \n Endpoint: %s \n User: %s \n Database: %s", p.RDSEndpoint, p.User, p.Database)
109126

110127
dsnURL := &url.URL{
111128
Scheme: "postgresql",
@@ -131,11 +148,41 @@ func NewPostgresqlConnectorWithIAMAuth(ctx context.Context, cfg *IAMAuthConfig)
131148
return nil, errors.New("AWS region is not configured")
132149
}
133150

151+
creds := awsCfg.Credentials
152+
153+
// Cross-account support:
154+
// If AssumeRoleARN is set, assume a role in the RDS account (Account A)
155+
// using the ECS task role creds from Account B as the source credentials.
156+
if cfg.AssumeRoleARN != "" {
157+
log.Printf("RDS IAM Assuming Role: %s for \n Endpoint: %s \n User: %s \n Database: %s", cfg.AssumeRoleARN, cfg.RDSEndpoint, cfg.User, cfg.Database)
158+
stsClient := sts.NewFromConfig(awsCfg)
159+
160+
sessionName := cfg.AssumeRoleSessionName
161+
if sessionName == "" {
162+
sessionName = "pgutils-rds-iam"
163+
}
164+
165+
assumeProvider := stscreds.NewAssumeRoleProvider(stsClient, cfg.AssumeRoleARN, func(assumeRoleOpts *stscreds.AssumeRoleOptions) {
166+
assumeRoleOpts.RoleSessionName = sessionName
167+
168+
if cfg.AssumeRoleExternalID != "" {
169+
assumeRoleOpts.ExternalID = aws.String(cfg.AssumeRoleExternalID)
170+
}
171+
172+
if cfg.AssumeRoleDuration != 0 {
173+
assumeRoleOpts.Duration = cfg.AssumeRoleDuration
174+
}
175+
})
176+
177+
// Cache to avoid calling STS too frequently.
178+
creds = aws.NewCredentialsCache(assumeProvider)
179+
}
180+
134181
return &PostgresqlConnector{
135182
baseConnectionStringProvider: &iamAuthConnectionStringProvider{
136183
IAMAuthConfig: *cfg,
137184
region: awsCfg.Region,
138-
creds: awsCfg.Credentials,
185+
creds: creds,
139186
},
140187
}, nil
141188
}
@@ -145,4 +192,3 @@ func OpenDB(conn *PostgresqlConnector) *sqlx.DB {
145192
sqlDB := sql.OpenDB(conn)
146193
return sqlx.NewDb(sqlDB, "postgres")
147194
}
148-

0 commit comments

Comments
 (0)