Skip to content

Commit

Permalink
Add support for automatic database users for Postgres (#25614)
Browse files Browse the repository at this point in the history
  • Loading branch information
r0mant committed May 18, 2023
1 parent 4741666 commit 79b54d8
Show file tree
Hide file tree
Showing 43 changed files with 4,121 additions and 2,526 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -1001,6 +1001,7 @@ ADDLICENSE_ARGS := -c 'Gravitational, Inc' -l apache \
-ignore '**/*.tf' \
-ignore '**/*.yaml' \
-ignore '**/*.yml' \
-ignore '**/*.sql' \
-ignore '**/Dockerfile' \
-ignore 'api/version.go' \
-ignore 'docs/pages/includes/**/*.go' \
Expand Down
4 changes: 4 additions & 0 deletions api/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,10 @@ const (
// allowed database users.
TraitDBUsers = "db_users"

// TraitDBRoles is the name of the role variable used to store
// allowed database roles.
TraitDBRoles = "db_roles"

// TraitAWSRoleARNs is the name of the role variable used to store
// allowed AWS role ARNs.
TraitAWSRoleARNs = "aws_role_arns"
Expand Down
2 changes: 2 additions & 0 deletions api/proto/teleport/legacy/types/events/events.proto
Original file line number Diff line number Diff line change
Expand Up @@ -2395,6 +2395,8 @@ message DatabaseMetadata {
string DatabaseGCPProjectID = 9 [(gogoproto.jsontag) = "db_gcp_project_id,omitempty"];
// DatabaseGCPInstanceID is instance ID for GCP hosted databases.
string DatabaseGCPInstanceID = 10 [(gogoproto.jsontag) = "db_gcp_instance_id,omitempty"];
// DatabaseRoles is a list of database roles for auto-provisioned users.
repeated string DatabaseRoles = 11 [(gogoproto.jsontag) = "db_roles,omitempty"];
}

// DatabaseCreate is emitted when a new database resource is created.
Expand Down
19 changes: 19 additions & 0 deletions api/proto/teleport/legacy/types/types.proto
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,15 @@ message DatabaseSpecV3 {
(gogoproto.nullable) = false,
(gogoproto.jsontag) = "mysql,omitempty"
];
// AdminUser is the database admin user for automatic user provisioning.
DatabaseAdminUser AdminUser = 11 [(gogoproto.jsontag) = "admin_user,omitempty"];
}

// DatabaseAdminUser contains information about privileged database user used
// for automatic user provisioning.
message DatabaseAdminUser {
// Name is the username of the privileged database user.
string Name = 1 [(gogoproto.jsontag) = "name"];
}

// DatabaseStatusV3 contains runtime information about the database.
Expand Down Expand Up @@ -2409,6 +2418,13 @@ message RoleOptions {
(gogoproto.jsontag) = "create_desktop_user",
(gogoproto.customtype) = "BoolOption"
];

// CreateDatabaseUser enabled automatic database user creation.
BoolValue CreateDatabaseUser = 27 [
(gogoproto.nullable) = true,
(gogoproto.jsontag) = "create_db_user",
(gogoproto.customtype) = "BoolOption"
];
}

message RecordSession {
Expand Down Expand Up @@ -2587,6 +2603,9 @@ message RoleConditions {

// DesktopGroups is a list of groups for created desktop users to be added to
repeated string DesktopGroups = 28 [(gogoproto.jsontag) = "desktop_groups,omitempty"];

// DatabaseRoles is a list of databases roles for automatic user creation.
repeated string DatabaseRoles = 29 [(gogoproto.jsontag) = "db_roles,omitempty"];
}

// KubernetesResource is the Kubernetes resource identifier.
Expand Down
4 changes: 4 additions & 0 deletions api/types/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,10 @@ const (
// CloudLabel is used to identify the cloud where the resource was discovered.
CloudLabel = TeleportNamespace + "/cloud"

// DatabaseAdminLabel is used to identify database admin user for auto-
// discovered databases.
DatabaseAdminLabel = TeleportNamespace + "/db-admin"

// CloudAWS identifies that a resource was discovered in AWS.
CloudAWS = "AWS"
// CloudAzure identifies that a resource was discovered in Azure.
Expand Down
39 changes: 39 additions & 0 deletions api/types/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,11 @@ type Database interface {
RequireAWSIAMRolesAsUsers() bool
// Copy returns a copy of this database resource.
Copy() *DatabaseV3
// GetAdminUser returns database privileged user information.
GetAdminUser() string
// SupportsAutoUsers returns true if this database supports automatic
// user provisioning.
SupportsAutoUsers() bool
}

// NewDatabaseV3 creates a new database resource.
Expand Down Expand Up @@ -268,6 +273,29 @@ func (d *DatabaseV3) SetURI(uri string) {
d.Spec.URI = uri
}

// GetAdminUser returns database privileged user information.
func (d *DatabaseV3) GetAdminUser() string {
// First check the spec.
if d.Spec.AdminUser != nil {
return d.Spec.AdminUser.Name
}
// If it's not in the spec, check labels (for auto-discovered databases).
return d.Metadata.Labels[DatabaseAdminLabel]
}

// SupportsAutoUsers returns true if this database supports automatic user
// provisioning.
func (d *DatabaseV3) SupportsAutoUsers() bool {
switch d.GetProtocol() {
case DatabaseProtocolPostgreSQL:
switch d.GetType() {
case DatabaseTypeSelfHosted, DatabaseTypeRDS:
return true
}
}
return false
}

// GetCA returns the database CA certificate. If more than one CA is set, then
// the user provided CA is returned first (Spec field).
// Auto-downloaded CA certificate is returned otherwise.
Expand Down Expand Up @@ -738,6 +766,14 @@ func (d *DatabaseV3) CheckAndSetDefaults() error {
return trace.BadParameter("database %q missing Cloud SQL project ID",
d.GetName())
}

// Admin user (for automatic user provisioning) is only supported for
// PostgreSQL currently.
if d.GetAdminUser() != "" && !d.SupportsAutoUsers() {
return trace.BadParameter("cannot set admin user on database %q: %v/%v databases don't support automatic user provisioning yet",
d.GetName(), d.GetProtocol(), d.GetType())
}

return nil
}

Expand Down Expand Up @@ -850,6 +886,9 @@ func (d *DatabaseV3) RequireAWSIAMRolesAsUsers() bool {
}

const (
// DatabaseProtocolPostgreSQL is the PostgreSQL database protocol.
DatabaseProtocolPostgreSQL = "postgres"

// DatabaseTypeSelfHosted is the self-hosted type of database.
DatabaseTypeSelfHosted = "self-hosted"
// DatabaseTypeRDS is AWS-hosted RDS or Aurora database.
Expand Down

0 comments on commit 79b54d8

Please sign in to comment.