Skip to content

Commit

Permalink
feat: Add options to specify AWS credential source for RDS functions
Browse files Browse the repository at this point in the history
Currently AWS credentials are always taken from the profile, which limits
the ability to export into non-s3 storage and s3 storage in other regions.

Added options to specify a separate secret or use IAM role for service account.
  • Loading branch information
hairyhum committed Dec 13, 2024
1 parent de1859e commit baeff37
Show file tree
Hide file tree
Showing 7 changed files with 338 additions and 145 deletions.
67 changes: 56 additions & 11 deletions docs_new/functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -938,6 +938,15 @@ Arguments:
| ---------- | :------: | ------ | ----------- |
| instanceID | Yes | string | ID of RDS instance you want to create snapshot of |
| dbEngine | No | string | Required in case of RDS Aurora instance. Supported DB Engines: `aurora` `aurora-mysql` and `aurora-postgresql` |
| credentialsSource | No | string | Source for aws credentials. Supported sources: `profile`, `secret`, `serviceaccount`. Default value is `profile` |
| credentialsSecret | No | string | Secret to get credentials from. Only used with `credentialsSource: secret`. Secret with this name should be referenced in the Actionset |
| region | No | string | AWS region to use. Derived from profile or serviceaccount if not set |

::: tip NOTE

`credentialsSource: serviceaccount` uses kanister operator service account. IAM role for service
account should be set up to access the RDS database.
:::

Outputs:

Expand Down Expand Up @@ -994,6 +1003,10 @@ Arguments:
| image | No | string | kanister-tools image to be used for running export job |
| podAnnotations | No | map[string]string | custom annotations for the temporary pod that gets created |
| podLabels | No | map[string]string | custom labels for the temporary pod that gets created |
| credentialsSource | No | string | Source for aws credentials. Supported sources: `profile`, `secret`, `serviceaccount`. Default value is `profile` |
| credentialsSecret | No | string | Secret to get credentials from. Only used with `credentialsSource: secret`. Secret with this name should be [referenced in the Actionset](templates.html#secrets) |
| region | No | string | AWS region to use. Derived from profile or serviceaccount if not set |


::: tip NOTE

Expand All @@ -1006,6 +1019,19 @@ associated with instance with `instanceID` and will pass the same. - If
set, `default` DB Subnet group will be used.
:::

::: tip NOTE

If `credentialsSource` is configured to `profile` (default), the profile used has to be
an S3 profile in the same region as the database snapshot.
It's recommended to export to another region. To do that `credentialSource: secret` or `credentialSource: serviceaccount` can be used.
:::

::: tip NOTE

`credentialsSource: serviceaccount` uses kanister operator service account. IAM role for service
account should be set up to access the RDS database.
:::

Outputs:

| Output | Type | Description |
Expand Down Expand Up @@ -1069,13 +1095,13 @@ stored in an object storage.

::: tip NOTE

\- If [snapshotID] is set, the function will restore RDS
instance from the RDS snapshot. Otherwise *backupID* needs
to be set to restore the RDS instance from data dump. - While restoring
the data from RDS snapshot if RDS instance (where we have to restore the
data) doesn\'t exist, the RDS instance will be created. But if the data
- If `snapshotID` is set, the function will restore RDS
instance from the RDS snapshot. Otherwise `backupID` needs
to be set to restore the RDS instance from data dump.
- While restoring the data from RDS snapshot if RDS instance (where we have to restore the
data) doesn't exist, the RDS instance will be created. But if the data
is being restored from the Object Storage (data dump) and the RDS
instance doesn\'t exist new RDS instance will not be created and will
instance doesn't exist new RDS instance will not be created and will
result in an error.
:::

Expand All @@ -1096,15 +1122,25 @@ Arguments:
| image | No | string | kanister-tools image to be used for running restore, only relevant when restoring from data dump (if `snapshotID` is empty) |
| podAnnotations | No | map[string]string | custom annotations for the temporary pod that gets created |
| podLabels | No | map[string]string | custom labels for the temporary pod that gets created |
| credentialsSource | No | string | Source for aws credentials. Supported sources: `profile`, `secret`, `serviceaccount`. Default value is `profile` |
| credentialsSecret | No | string | Secret to get credentials from. Only used with `credentialsSource: secret`. Secret with this name should be referenced in the Actionset |
| region | No | string | AWS region to use. Derived from profile or serviceaccount if not set |


::: tip NOTE

\- If `snapshotID` is not set, restore will be done from data dump. In
that case `backupID` [arg] is required. - If
`securityGroupID` argument is not set, `RestoreRDSSnapshot` will find
- If `snapshotID` is not set, restore will be done from data dump. In
that case `backupID` arg is required.
- If `securityGroupID` argument is not set, `RestoreRDSSnapshot` will find
out Security Group IDs associated with instance with `instanceID` and
will pass the same. - If `dbSubnetGroup` argument is not set, `default`
DB Subnet group will be used.
will pass the same.
- If `dbSubnetGroup` argument is not set, `default` DB Subnet group will be used.
:::

::: tip NOTE

`credentialsSource: serviceaccount` uses kanister operator service account. IAM role for service
account should be set up to access the RDS database.
:::

Outputs:
Expand Down Expand Up @@ -1153,6 +1189,15 @@ Arguments:
| Argument | Required | Type | Description |
| ---------- | :------: | ------ | ----------- |
| snapshotID | No | string | ID of the RDS snapshot |
| credentialsSource | No | string | Source for aws credentials. Supported sources: `profile`, `secret`, `serviceaccount`. Default value is `profile` |
| credentialsSecret | No | string | Secret to get credentials from. Only used with `credentialsSource: secret`. Secret with this name should be referenced in the Actionset |
| region | No | string | AWS region to use. Derived from profile or serviceaccount if not set |

::: tip NOTE

`credentialsSource: serviceaccount` uses kanister operator service account. IAM role for service
account should be set up to access the RDS database.
:::

Example:

Expand Down
19 changes: 11 additions & 8 deletions pkg/function/create_rds_snapshot.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,15 +74,10 @@ func (*createRDSSnapshotFunc) Name() string {
return CreateRDSSnapshotFuncName
}

func createRDSSnapshot(ctx context.Context, instanceID string, dbEngine RDSDBEngine, profile *param.Profile) (map[string]interface{}, error) {
func createRDSSnapshot(ctx context.Context, instanceID string, dbEngine RDSDBEngine, credentialsSource awsCredentialsSource, tp param.TemplateParams) (map[string]interface{}, error) {
var allocatedStorage int64
// Validate profile
if err := ValidateProfile(profile); err != nil {
return nil, errkit.Wrap(err, "Profile Validation failed")
}

// Get aws config from profile
awsConfig, region, err := getAWSConfigFromProfile(ctx, profile)
awsConfig, region, err := getAwsConfig(ctx, credentialsSource, tp)
if err != nil {
return nil, errkit.Wrap(err, "Failed to get AWS creds from profile")
}
Expand Down Expand Up @@ -185,7 +180,12 @@ func (crs *createRDSSnapshotFunc) Exec(ctx context.Context, tp param.TemplatePar
return nil, err
}

return createRDSSnapshot(ctx, instanceID, dbEngine, tp.Profile)
credentialsSource, err := parseCredentialsSource(args)
if err != nil {
return nil, err
}

return createRDSSnapshot(ctx, instanceID, dbEngine, *credentialsSource, tp)
}

func (*createRDSSnapshotFunc) RequiredArgs() []string {
Expand All @@ -198,6 +198,9 @@ func (crs *createRDSSnapshotFunc) Arguments() []string {
return []string{
CreateRDSSnapshotInstanceIDArg,
CreateRDSSnapshotDBEngine,
CredentialsSourceArg,
CredentialsSecretArg,
RegionArg,
}
}

Expand Down
21 changes: 12 additions & 9 deletions pkg/function/delete_rds_snapshot.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,16 +55,11 @@ func (*deleteRDSSnapshotFunc) Name() string {
return DeleteRDSSnapshotFuncName
}

func deleteRDSSnapshot(ctx context.Context, snapshotID string, profile *param.Profile, dbEngine RDSDBEngine) error {
// Validate profile
if err := ValidateProfile(profile); err != nil {
return errkit.Wrap(err, "Profile Validation failed")
}

func deleteRDSSnapshot(ctx context.Context, snapshotID string, credentialsSource awsCredentialsSource, tp param.TemplateParams, dbEngine RDSDBEngine) error {
// Get aws config from profile
awsConfig, region, err := getAWSConfigFromProfile(ctx, profile)
awsConfig, region, err := getAwsConfig(ctx, credentialsSource, tp)
if err != nil {
return errkit.Wrap(err, "Failed to get AWS creds from profile")
return errkit.Wrap(err, "Failed to get AWS creds")
}

// Create rds client
Expand Down Expand Up @@ -130,7 +125,12 @@ func (d *deleteRDSSnapshotFunc) Exec(ctx context.Context, tp param.TemplateParam
return nil, err
}

return nil, deleteRDSSnapshot(ctx, snapshotID, tp.Profile, dbEngine)
credentialsSource, err := parseCredentialsSource(args)
if err != nil {
return nil, err
}

return nil, deleteRDSSnapshot(ctx, snapshotID, *credentialsSource, tp, dbEngine)
}

func (*deleteRDSSnapshotFunc) RequiredArgs() []string {
Expand All @@ -141,6 +141,9 @@ func (*deleteRDSSnapshotFunc) Arguments() []string {
return []string{
DeleteRDSSnapshotSnapshotIDArg,
CreateRDSSnapshotDBEngine,
CredentialsSourceArg,
CredentialsSecretArg,
RegionArg,
}
}

Expand Down
19 changes: 15 additions & 4 deletions pkg/function/export_rds_snapshot_location.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,19 +96,21 @@ func exportRDSSnapshotToLoc(
backupPrefix string,
dbEngine RDSDBEngine,
sgIDs []string,
profile *param.Profile,
credentialsSource awsCredentialsSource,
tp param.TemplateParams,
postgresToolsImage string,
annotations,
labels map[string]string,
) (map[string]interface{}, error) {
profile := tp.Profile
// Validate profilextractDumpFromDBe
if err := ValidateProfile(profile); err != nil {
return nil, errkit.Wrap(err, "Profile Validation failed")
}

awsConfig, region, err := getAWSConfigFromProfile(ctx, profile)
awsConfig, region, err := getAwsConfig(ctx, credentialsSource, tp)
if err != nil {
return nil, errkit.Wrap(err, "Failed to get AWS creds from profile")
return nil, errkit.Wrap(err, "Failed to get AWS creds")
}

// Create rds client
Expand Down Expand Up @@ -259,6 +261,11 @@ func (e *exportRDSSnapshotToLocationFunc) Exec(ctx context.Context, tp param.Tem
return nil, err
}

credentialsSource, err := parseCredentialsSource(args)
if err != nil {
return nil, err
}

return exportRDSSnapshotToLoc(
ctx,
namespace,
Expand All @@ -271,7 +278,8 @@ func (e *exportRDSSnapshotToLocationFunc) Exec(ctx context.Context, tp param.Tem
backupArtifact,
dbEngine,
sgIDs,
tp.Profile,
*credentialsSource,
tp,
postgresToolsImage,
annotations,
labels,
Expand Down Expand Up @@ -301,6 +309,9 @@ func (*exportRDSSnapshotToLocationFunc) Arguments() []string {
ExportRDSSnapshotToLocDBSubnetGroupArg,
PodAnnotationsArg,
PodLabelsArg,
CredentialsSourceArg,
CredentialsSecretArg,
RegionArg,
}
}

Expand Down
Loading

0 comments on commit baeff37

Please sign in to comment.