Skip to content
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cloud iam auth #13

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
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
172 changes: 172 additions & 0 deletions 20230729-db-cloud-auth.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
# Meta
[meta]: #meta
- Name: Cloud Authentication for database access
- Start Date: 2030-07-29
- Author(s): [KlausVii](https://github.com/KlausVii)
- Status: Draft <!-- Acceptable values: Draft, Approved, On Hold, Superseded -->
- RFC Pull Request: (leave blank)
- Relevant Issues: https://github.com/openfga/openfga/issues/870
- Supersedes: "N/A"

# Summary
[summary]: #summary

Many users run OpenFGA in a cloud environment, and these cloud providers often provide alternate authentication methods for their databases,
such as [AWS RDS IAM](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.IAMDBAuth.html) and [GCP Cloud SQL Go Connector](https://cloud.google.com/sql/docs/postgres/samples/cloud-sql-postgres-databasesql-connect-connector).
This RFC proposes a new authentication method that allows users to authenticate against a cloud provider, starting with AWS RDS support.

# Motivation
[motivation]: #motivation

- Why should we do this?
- Enabling cloud authentication methods will allow users to deploy OpenFGA faster and more securely.
- Personally at our workplace all our other services authenticate with RDS IAM and not being able to do so with OpenFGA adds friction.
- I imagine there are similar issues [on other cloud providers](https://cloud.google.com/sql/docs/mysql/connect-admin-ip#connect-ssl).
- What use cases does it support?
- Users will be able to use their cloud provider's authentication method to authenticate against their database.
- What is the expected outcome?
- openFGA supports AWS IAM.
- it is easy to extend to other cloud providers.

# What it is
[what-it-is]: #what-it-is

Add support for cloud provider authentication methods to openFGA, so that operators can more easily deploy openFGA in a cloud environment.

# How it Works
[how-it-works]: #how-it-works

## New configuration options

The most straight forward option would be to introduce a new `datastore` string option `auth_method`. The user could then
select from a list of supported authentication methods. If left blank, the default would be to use the existing username and password
specified by the URI.

`-datastore.auth_method (string): "aws_rds_iam" | "gcp_cloud_iam" | etc`

Alternatively, a set of boolean flags could be used, but that seems cumbersome since only one would ever be used at a time.

`-datastore.aws_rds_iam_auth (bool)`

#### Inclusion of cloud provider SDKs configuration

Including the provider specific options, like `AWS_REGION`, seems unnecessary since the SDK's themselves are able to
aqcuire these from the environment automatically. And adding them would make the configuration more complex and dependent on the SDKs.

## Implementation

Authentication would need to be implemented for both databases supported by openFGA: postgres and mysql.
Copy link
Contributor

@jon-whit jon-whit Aug 30, 2023

Choose a reason for hiding this comment

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

As a maintainer team we're worried about introducing these cloud specific database connection functionalities in OpenFGA, because it will be cumbersome to manage. Depending on more of a community driven and community based standard for this functionality would be preferable as it allows our maintainer team to leverage a larger community to help evolve and maintain these cloud IAM mechanisms.

For this reason, we'd like to see an exploration of the go-cloud CDK (mentioned in the Prior Art section below) before we proceed forward. Specifically,

  • Are there features/functionalities that the Go Cloud CDK does not address that are pertinent to the usage patterns for these proprietary cloud IAM protocols? If so, what are the limitations? For example, can you use the assumed role functionality of AWS IAM etc..

  • Does the usage of the cloud specific sql providers in the Go Cloud CDK necessitate a specific underlying driver (e.g. pgx, pql, etc..)? Or can you bring your own driver?

    From the looks of it you can use whatever underlying driver you want (see https://github.com/google/go-cloud/blob/master/samples/guestbook/wire_gen.go#L16C34-L16C34 as an example). But this needs to be confirmed.

If you'd be willing to help with this discovery @KlausVii we'd really appreciate it. If not though, our next step as a maintainer team is to do some more discovery with the go-cloud SDK and see how it works for this use case.

We have used the go-cloud SDK elsewhere and have had positive experiences with it, so we at least have some confidence in it as a potential solution.

Copy link
Author

Choose a reason for hiding this comment

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

The one feature missing from go-cloud is fetching the authentication token from AWS, which is used as the password for your db connection. The issue this causes is that the token is only valid for 15min and if it is not refreshed, new connections will fail after the token expires.

I dug through the go-cloud source code , and could not find any code for retrieving this token. They seem to only inject some certificates for the AWS connection and expect the user to provide the password (which will expire if not refreshed) at initialisation.

This is why the extra work is required for the AWS IAM auth.

As to using go-cloud as at the underlying db driver for all the implantations, that should work just fine, it just does not provide a full end to end solution for AWS like it does GCP (might be a bit of google bias given its a google library).

Do let me know if I missed something with go-cloud, happy to be proven wrong.

As far as the maintenance burden, it should not be too high. The auth token just needs be fetched, injected, and refreshed close to expiry; this amounts to about 80 LoC to keep up to date, and I imagine the AWS side will remain very stable.

My draft implementation is about an evening's of work away from completion, so if I've somewhat convinced you, I'd be happy get into shape and open up a PR to show what this whole thing would look like.


All the cloud provider connectors should return a `sql.DB`, so that adding new ones is simple as adding a new case:
```go
var db *sql.DB
switch cfg.AuthMethod {
case "aws_rds_iam":
db, err = openRDS(uri, cfg)
case "":
db, err = sql.Open("pgx", uri.String())
default:
return nil, fmt.Errorf("unsupported auth_method: %s", cfg.AuthMethod)
}
```

### Platforms
#### AWS

AWS RDS IAM authentication is done by [acquiring an authentication token](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.IAMDBAuth.html)
from the AWS SDK and passing it as the password. This token is valid for 15 minutes, so it needs to be refreshed periodically.
This requires a background process to refresh the token within application.

#### GCP

GCP Cloud SQL Go Connector authentication is done via [a special dialer](https://cloud.google.com/sql/docs/postgres/samples/cloud-sql-postgres-databasesql-connect-connector).
This method is simpler than AWS RDS IAM, since it does not require a background process to refresh the token. I think [go-cloud](https://github.com/google/go-cloud)
provides this functionality out of the box, so that could be used.

### Database connectors

Below are some examples of how the connectors could be implemented with AWS RDS IAM for both postgres and mysql.

#### Postgres

Since openFGA uses pgx, we can use the [BeforeConnect](https://github.com/jackc/pgx/blob/d626dfe94e250e911b77ac929e2be06f81042bd0/pgxpool/pool.go#L109)
hook to provide AWS RDS IAM tokens.

```go
func openRDS(uri *url.URL, cfg *sqlcommon.Config) (*sql.DB, error) {
ctx := context.Background()
iam, err := newIAM(ctx, cfg.Username, uri.Hostname(), uri.Port())
if err != nil {
return nil, err
}
conf, err := pgx.ParseConfig(uri.String())
if err != nil {
return nil, err
}
connector := pgxstd.GetConnector(*conf, pgxstd.OptionBeforeConnect(iam.BeforeConnect))
db := sql.OpenDB(connector)
return db, nil
}
```

#### Mysql

For mysql we need to wrap the sql connector to modify the connection string. This is done by implementing the [Driver interface](https://golang.org/pkg/database/sql/driver/#Driver).

```go
func (i *iam) Connect(ctx context.Context) (driver.Conn, error) {
token, isNew, err := i.getRDSAuthToken(ctx)
if err != nil {
return nil, err
}
if !isNew {
return i.baseConnector.Connect(ctx)
}
i.mysqlCfg.Passwd = token
i.baseConnector, err = mysql.NewConnector(i.mysqlCfg)
if err != nil {
return nil, err
}
return i.baseConnector.Connect(ctx)
}

func (i *iam) Driver() driver.Driver {
return i.baseConnector.Driver()
}

func open(...) (*sql.DB, error) {
i := newIAM(...)
return sql.OpenDB(i), nil
}
```
## Extensibility

This implementation would make it relatively simple to add new providers. You would just add a new case to `auth_method` and implement the connector.

# Migration
[migration]: #migration

There should not be any breaking changes just new configuration options.

# Drawbacks
[drawbacks]: #drawbacks
- Adds dependencies to cloud provider SDKs.

# Alternatives
[alternatives]: #alternatives

- What other designs have been considered?
- Why is this proposal the best?
- What is the impact of not doing this?

# Prior Art
[prior-art]: #prior-art

### [go-cloud](https://github.com/google/go-cloud)

Provides [IAM auth for GCP Cloud SQL](https://github.com/google/go-cloud/blob/master/postgres/gcppostgres/gcppostgres_test.go#L54), but not [AWS RDS](https://github.com/google/go-cloud/issues/3069).
Copy link
Contributor

Choose a reason for hiding this comment

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

go-cloud does support AWS RDS. This issue is outdated and has since been closed.

See https://gocloud.dev/howto/sql/#aws

Copy link
Author

Choose a reason for hiding this comment

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

There some support for RDS, but it is not complete (see my other comment), final comment on the issue also implied that they did not intend to add the IAM auth

Does provide a unified API for connecting to various cloud providers. Could be used for inspiration on how to structure the code and GCP implementation.

# Unresolved Questions
[unresolved-questions]: #unresolved-questions