Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

feat: add awsiamrds db auth driver#12566

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
f0ssel merged 21 commits intomainfromf0ssel/awsrdsiam
Mar 20, 2024
Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
Show all changes
21 commits
Select commitHold shift + click to select a range
d23ad15
feat: add awsrdsiam db auth connector
f0sselMar 12, 2024
f2426d1
fix parent name
f0sselMar 12, 2024
03eb9c1
wire to falgs
f0sselMar 14, 2024
1ff0291
add aws v2
f0sselMar 14, 2024
269097c
remove aws v1
f0sselMar 14, 2024
eba4c6b
fix function calls
f0sselMar 14, 2024
83d7101
make gen
f0sselMar 14, 2024
f25ae4e
implement yaml methods
f0sselMar 14, 2024
cb887c0
remove clibase
f0sselMar 18, 2024
c0bd787
remove diff
f0sselMar 18, 2024
891a7c0
Make gen
f0sselMar 18, 2024
7ab2e95
fix complexity
f0sselMar 18, 2024
b44becf
lint
f0sselMar 18, 2024
66c686d
update serpent
f0sselMar 18, 2024
a425f5b
update aws
f0sselMar 18, 2024
de7e7d9
log
f0sselMar 18, 2024
c256df3
add note
f0sselMar 19, 2024
c0a0515
rename awsrdsiam to awsiamrds to match v1
f0sselMar 19, 2024
6c3d73d
update golden
f0sselMar 19, 2024
c56fddc
rename files
f0sselMar 19, 2024
293140b
fix data races
f0sselMar 19, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 23 additions & 6 deletionscli/server.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -64,6 +64,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/awsiamrds"
"github.com/coder/coder/v2/coderd/database/dbmem"
"github.com/coder/coder/v2/coderd/database/dbmetrics"
"github.com/coder/coder/v2/coderd/database/dbpurge"
Expand DownExpand Up@@ -667,12 +668,7 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
options.Database = dbmem.New()
options.Pubsub = pubsub.NewInMemory()
} else {
dbURL, err := escapePostgresURLUserInfo(vals.PostgresURL.String())
if err != nil {
return xerrors.Errorf("escaping postgres URL: %w", err)
}

sqlDB, err := ConnectToPostgres(ctx, logger, sqlDriver, dbURL)
sqlDB, dbURL, err := getPostgresDB(ctx, logger, vals.PostgresURL.String(), codersdk.PostgresAuth(vals.PostgresAuth), sqlDriver)
if err != nil {
return xerrors.Errorf("connect to postgres: %w", err)
}
Expand DownExpand Up@@ -2548,3 +2544,24 @@ func signalNotifyContext(ctx context.Context, inv *serpent.Invocation, sig ...os
}
return inv.SignalNotifyContext(ctx, sig...)
}

func getPostgresDB(ctx context.Context, logger slog.Logger, postgresURL string, auth codersdk.PostgresAuth, sqlDriver string) (*sql.DB, string, error) {
dbURL, err := escapePostgresURLUserInfo(postgresURL)
if err != nil {
return nil, "", xerrors.Errorf("escaping postgres URL: %w", err)
}

if auth == codersdk.PostgresAuthAWSIAMRDS {
sqlDriver, err = awsiamrds.Register(ctx, sqlDriver)
if err != nil {
return nil, "", xerrors.Errorf("register aws rds iam auth: %w", err)
}
}

sqlDB, err := ConnectToPostgres(ctx, logger, sqlDriver, dbURL)
if err != nil {
return nil, "", xerrors.Errorf("connect to postgres: %w", err)
}

return sqlDB, dbURL, nil
}
20 changes: 19 additions & 1 deletioncli/server_createadminuser.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -13,6 +13,7 @@ import (
"cdr.dev/slog/sloggers/sloghuman"
"github.com/coder/coder/v2/cli/cliui"
"github.com/coder/coder/v2/coderd/database"
"github.com/coder/coder/v2/coderd/database/awsiamrds"
"github.com/coder/coder/v2/coderd/database/dbtime"
"github.com/coder/coder/v2/coderd/gitsshkey"
"github.com/coder/coder/v2/coderd/httpapi"
Expand All@@ -25,6 +26,7 @@ import (
func (r *RootCmd) newCreateAdminUserCommand() *serpent.Command {
var (
newUserDBURL string
newUserPgAuth string
newUserSSHKeygenAlgorithm string
newUserUsername string
newUserEmail string
Expand DownExpand Up@@ -62,7 +64,15 @@ func (r *RootCmd) newCreateAdminUserCommand() *serpent.Command {
newUserDBURL = url
}

sqlDB, err := ConnectToPostgres(ctx, logger, "postgres", newUserDBURL)
sqlDriver := "postgres"
if codersdk.PostgresAuth(newUserPgAuth) == codersdk.PostgresAuthAWSIAMRDS {
sqlDriver, err = awsiamrds.Register(inv.Context(), sqlDriver)
if err != nil {
return xerrors.Errorf("register aws rds iam auth: %w", err)
}
}

sqlDB, err := ConnectToPostgres(ctx, logger, sqlDriver, newUserDBURL)
if err != nil {
return xerrors.Errorf("connect to postgres: %w", err)
}
Expand DownExpand Up@@ -243,6 +253,14 @@ func (r *RootCmd) newCreateAdminUserCommand() *serpent.Command {
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: serpent.StringOf(&newUserDBURL),
},
serpent.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: serpent.EnumOf(&newUserPgAuth, codersdk.PostgresAuthDrivers...),
},
serpent.Option{
Env: "CODER_SSH_KEYGEN_ALGORITHM",
Flag: "ssh-keygen-algorithm",
Expand Down
3 changes: 3 additions & 0 deletionscli/testdata/coder_server_--help.golden
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -44,6 +44,9 @@ OPTIONS:
Separate multiple experiments with commas, or enter '*' to opt-in to
all available experiments.

--postgres-auth password|awsiamrds, $CODER_PG_AUTH (default: password)
Type of auth to use when connecting to postgres.

--postgres-url string, $CODER_PG_CONNECTION_URL
URL of a PostgreSQL database. If empty, PostgreSQL binaries will be
downloaded from Maven (https://repo1.maven.org/maven2) and store all
Expand Down
3 changes: 3 additions & 0 deletionscli/testdata/coder_server_create-admin-user_--help.golden
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -7,6 +7,9 @@ USAGE:
it to every organization.

OPTIONS:
--postgres-connection-auth password|awsiamrds, $CODER_PG_CONNECTION_AUTH (default: password)
Type of auth to use when connecting to postgres.

--email string, $CODER_EMAIL
The email of the new user. If not specified, you will be prompted via
stdin.
Expand Down
3 changes: 3 additions & 0 deletionscli/testdata/server-config.yaml.golden
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -411,6 +411,9 @@ cacheDir: [cache dir]
# Controls whether data will be stored in an in-memory database.
# (default: <unset>, type: bool)
inMemoryDatabase: false
# Type of auth to use when connecting to postgres.
# (default: password, type: enum[password\|awsiamrds])
pgAuth: password
# The algorithm to use for generating ssh keys. Accepted values are "ed25519",
# "ecdsa", or "rsa4096".
# (default: ed25519, type: string)
Expand Down
3 changes: 3 additions & 0 deletionscoderd/apidoc/docs.go
View file
Open in desktop

Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.

3 changes: 3 additions & 0 deletionscoderd/apidoc/swagger.json
View file
Open in desktop

Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.

84 changes: 84 additions & 0 deletionscoderd/database/awsiamrds/awsiamrds.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
package awsiamrds

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"
"golang.org/x/xerrors"
)

type awsIamRdsDriver struct {
parent driver.Driver
cfg aws.Config
}

var _ driver.Driver = &awsIamRdsDriver{}

// Register initializes and registers our aws iam rds wrapped database driver.
func Register(ctx context.Context, parentName string) (string, error) {
cfg, err := config.LoadDefaultConfig(ctx)
if err != nil {
return "", err
}

db, err := sql.Open(parentName, "")
if err != nil {
return "", err
}

// create a new aws iam rds driver
d := newDriver(db.Driver(), cfg)
name := fmt.Sprintf("%s-awsiamrds", parentName)
sql.Register(fmt.Sprintf("%s-awsiamrds", parentName), d)

return name, nil
}

// newDriver will create a new *AwsIamRdsDriver using the environment aws session.
func newDriver(parentDriver driver.Driver, cfg aws.Config) *awsIamRdsDriver {
return &awsIamRdsDriver{
parent: parentDriver,
cfg: cfg,
}
}

// Open creates a new connection to the database using the provided name.
func (d *awsIamRdsDriver) Open(name string) (driver.Conn, error) {
// set password with signed aws authentication token for the rds instance
nURL, err := getAuthenticatedURL(d.cfg, name)
if err != nil {
return nil, xerrors.Errorf("assigning authentication token to url: %w", err)
}

// make connection
conn, err := d.parent.Open(nURL)
if err != nil {
return nil, xerrors.Errorf("opening connection with %s: %w", nURL, err)
}

return conn, nil
}

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
}
50 changes: 50 additions & 0 deletionscoderd/database/awsiamrds/awsiamrds_test.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
package awsiamrds_test

import (
"context"
"os"
"testing"

"github.com/stretchr/testify/require"

"cdr.dev/slog/sloggers/slogtest"

"github.com/coder/coder/v2/cli"
awsrdsiam "github.com/coder/coder/v2/coderd/database/awsiamrds"
"github.com/coder/coder/v2/testutil"
)

func TestDriver(t *testing.T) {
t.Parallel()
// Be sure to set AWS_DEFAULT_REGION to the database region as well.
// Example:
// export AWS_DEFAULT_REGION=us-east-2;
// export DBAWSIAMRDS_TEST_URL="postgres://user@host:5432/dbname";
url := os.Getenv("DBAWSIAMRDS_TEST_URL")
if url == "" {
t.Skip()
}

ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitShort)
defer cancel()

sqlDriver, err := awsrdsiam.Register(ctx, "postgres")
require.NoError(t, err)

db, err := cli.ConnectToPostgres(ctx, slogtest.Make(t, nil), sqlDriver, url)
require.NoError(t, err)
defer func() {
_ = db.Close()
}()

i, err := db.QueryContext(ctx, "select 1;")
require.NoError(t, err)
defer func() {
_ = i.Close()
}()

require.True(t, i.Next())
var one int
require.NoError(t, i.Scan(&one))
require.Equal(t, 1, one)
}
22 changes: 22 additions & 0 deletionscodersdk/deployment.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -135,6 +135,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 PostgresAuthDrivers = []string{
string(PostgresAuthPassword),
string(PostgresAuthAWSIAMRDS),
}

// DeploymentValues is the central configuration values the coder server.
type DeploymentValues struct {
Verbose serpent.Bool `json:"verbose,omitempty"`
Expand All@@ -154,6 +166,7 @@ type DeploymentValues struct {
CacheDir serpent.String `json:"cache_directory,omitempty" typescript:",notnull"`
InMemoryDatabase serpent.Bool `json:"in_memory_database,omitempty" typescript:",notnull"`
PostgresURL serpent.String `json:"pg_connection_url,omitempty" typescript:",notnull"`
PostgresAuth string `json:"pg_auth,omitempty" typescript:",notnull"`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Is there a specific string format the connection has when connecting via AWS IAM? I think it'd be preferred to check for that over adding a new server option.

Copy link
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Just a missing password field, maybe an AWS domain in the URL, but I don't think there's anything that's enough to make an inference.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

One thing that might be possible is if we detected the URL scheme and had people setawsiamrds://... instead ofpostgres://, or add a query param? It is unforunate we need a new flag just for aws auth, but it's probable we would exapand this in the future. My only worry is that just detecting it in the connection string would be non-obvious, since I haven't really seen it anywhere else, but to be fair I haven't really done much research.

Copy link
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Yeah I wouldn't wanna change the protocol because that kinda implies it's not speakingpostgres protocol. I think given we may have other auth schemes in the future we need to support, a flag seems fine to me and better than any parsing options I can think of.

OAuth2 OAuth2Config `json:"oauth2,omitempty" typescript:",notnull"`
OIDC OIDCConfig `json:"oidc,omitempty" typescript:",notnull"`
Telemetry TelemetryConfig `json:"telemetry,omitempty" typescript:",notnull"`
Expand DownExpand Up@@ -1630,6 +1643,15 @@ when required by your organization's security policy.`,
Annotations: serpent.Annotations{}.Mark(annotationSecretKey, "true"),
Value: &c.PostgresURL,
},
{
Name: "Postgres Auth",
Description: "Type of auth to use when connecting to postgres.",
Flag: "postgres-auth",
Env: "CODER_PG_AUTH",
Default: "password",
Value: serpent.EnumOf(&c.PostgresAuth, PostgresAuthDrivers...),
YAML: "pgAuth",
},
{
Name: "Secure Auth Cookie",
Description: "Controls if the 'Secure' property is set on browser session cookies.",
Expand Down
1 change: 1 addition & 0 deletionsdocs/api/general.md
View file
Open in desktop

Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.

3 changes: 3 additions & 0 deletionsdocs/api/schemas.md
View file
Open in desktop

Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.

11 changes: 11 additions & 0 deletionsdocs/cli/server.md
View file
Open in desktop

Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.

10 changes: 10 additions & 0 deletionsdocs/cli/server_create-admin-user.md
View file
Open in desktop

Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.

Loading

[8]ページ先頭

©2009-2025 Movatter.jp