Skip to content

Commit c4534cd

Browse files
feat: Add options to specify AWS credential source for RDS functions (#3289)
Signed-off-by: Daniil Fedotov <[email protected]> Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
1 parent c06c8d5 commit c4534cd

File tree

10 files changed

+431
-173
lines changed

10 files changed

+431
-173
lines changed

docs/functions.md

Lines changed: 56 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -938,6 +938,15 @@ Arguments:
938938
| ---------- | :------: | ------ | ----------- |
939939
| instanceID | Yes | string | ID of RDS instance you want to create snapshot of |
940940
| dbEngine | No | string | Required in case of RDS Aurora instance. Supported DB Engines: `aurora` `aurora-mysql` and `aurora-postgresql` |
941+
| credentialsSource | No | string | Source for aws credentials. Supported sources: `profile`, `secret`, `serviceaccount`. Default value is `profile` |
942+
| credentialsSecret | No | string | Secret to get credentials from. Only used with `credentialsSource: secret`. Secret with this name should be referenced in the Actionset |
943+
| region | No | string | AWS region to use. Derived from profile or serviceaccount if not set |
944+
945+
::: tip NOTE
946+
947+
`credentialsSource: serviceaccount` uses kanister operator service account. IAM role for service
948+
account should be set up to access the RDS database.
949+
:::
941950

942951
Outputs:
943952

@@ -994,6 +1003,10 @@ Arguments:
9941003
| image | No | string | kanister-tools image to be used for running export job |
9951004
| podAnnotations | No | map[string]string | custom annotations for the temporary pod that gets created |
9961005
| podLabels | No | map[string]string | custom labels for the temporary pod that gets created |
1006+
| credentialsSource | No | string | Source for aws credentials. Supported sources: `profile`, `secret`, `serviceaccount`. Default value is `profile` |
1007+
| 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) |
1008+
| region | No | string | AWS region to use. Derived from profile or serviceaccount if not set |
1009+
9971010

9981011
::: tip NOTE
9991012

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

1022+
::: tip NOTE
1023+
1024+
If `credentialsSource` is configured to `profile` (default behaviour), the profile used has to be
1025+
an S3 profile configured with the same region as the database snapshot.
1026+
If it's required to export to another region, `credentialSource: secret` or `credentialSource: serviceaccount` can be used.
1027+
:::
1028+
1029+
::: tip NOTE
1030+
1031+
`credentialsSource: serviceaccount` uses kanister operator service account. IAM role for service
1032+
account should be set up to access the RDS database.
1033+
:::
1034+
10091035
Outputs:
10101036

10111037
| Output | Type | Description |
@@ -1069,13 +1095,13 @@ stored in an object storage.
10691095

10701096
::: tip NOTE
10711097

1072-
\- If [snapshotID] is set, the function will restore RDS
1073-
instance from the RDS snapshot. Otherwise *backupID* needs
1074-
to be set to restore the RDS instance from data dump. - While restoring
1075-
the data from RDS snapshot if RDS instance (where we have to restore the
1076-
data) doesn\'t exist, the RDS instance will be created. But if the data
1098+
- If `snapshotID` is set, the function will restore RDS
1099+
instance from the RDS snapshot. Otherwise `backupID` needs
1100+
to be set to restore the RDS instance from data dump.
1101+
- While restoring the data from RDS snapshot if RDS instance (where we have to restore the
1102+
data) doesn't exist, the RDS instance will be created. But if the data
10771103
is being restored from the Object Storage (data dump) and the RDS
1078-
instance doesn\'t exist new RDS instance will not be created and will
1104+
instance doesn't exist new RDS instance will not be created and will
10791105
result in an error.
10801106
:::
10811107

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

11001130
::: tip NOTE
11011131

1102-
\- If `snapshotID` is not set, restore will be done from data dump. In
1103-
that case `backupID` [arg] is required. - If
1104-
`securityGroupID` argument is not set, `RestoreRDSSnapshot` will find
1132+
- If `snapshotID` is not set, restore will be done from data dump. In
1133+
that case `backupID` arg is required.
1134+
- If `securityGroupID` argument is not set, `RestoreRDSSnapshot` will find
11051135
out Security Group IDs associated with instance with `instanceID` and
1106-
will pass the same. - If `dbSubnetGroup` argument is not set, `default`
1107-
DB Subnet group will be used.
1136+
will pass the same.
1137+
- If `dbSubnetGroup` argument is not set, `default` DB Subnet group will be used.
1138+
:::
1139+
1140+
::: tip NOTE
1141+
1142+
`credentialsSource: serviceaccount` uses kanister operator service account. IAM role for service
1143+
account should be set up to access the RDS database.
11081144
:::
11091145

11101146
Outputs:
@@ -1153,6 +1189,15 @@ Arguments:
11531189
| Argument | Required | Type | Description |
11541190
| ---------- | :------: | ------ | ----------- |
11551191
| snapshotID | No | string | ID of the RDS snapshot |
1192+
| credentialsSource | No | string | Source for aws credentials. Supported sources: `profile`, `secret`, `serviceaccount`. Default value is `profile` |
1193+
| credentialsSecret | No | string | Secret to get credentials from. Only used with `credentialsSource: secret`. Secret with this name should be referenced in the Actionset |
1194+
| region | No | string | AWS region to use. Derived from profile or serviceaccount if not set |
1195+
1196+
::: tip NOTE
1197+
1198+
`credentialsSource: serviceaccount` uses kanister operator service account. IAM role for service
1199+
account should be set up to access the RDS database.
1200+
:::
11561201

11571202
Example:
11581203

examples/aws-rds/postgresql/README.md

Lines changed: 76 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ aws rds wait db-instance-available --db-instance-identifier=test-postgresql-inst
4545

4646
Create a configmap which contains information to connect to the RDS DB instance
4747

48-
```
48+
```yaml
4949
apiVersion: v1
5050
kind: ConfigMap
5151
metadata:
@@ -82,6 +82,32 @@ data operations such as backup should go. This is stored as a `profiles.cr.kanis
8282
requires a Profile reference to complete the action. This CR (`profiles.cr.kanister.io`)
8383
can be shared between Kanister-enabled application instances.
8484

85+
### Configure a secret to access RDS
86+
87+
By default the blueprints in this example are using credentials from the profile to access RDS
88+
resources.
89+
90+
If you want to export your backups to a different region or a different object store (recommended),
91+
you need to provide alternative credential configuration.
92+
93+
Here we use k8s secret with AWS credentials.
94+
You need to make sure credentials provided in this secret can be used to access RDS operations.
95+
96+
```yaml
97+
---
98+
apiVersion: v1
99+
kind: Secret
100+
metadata:
101+
name: rds-secret
102+
namespace: pgtestrds
103+
type: secrets.kanister.io/aws
104+
data:
105+
aws_access_key_id: "<your access key id>"
106+
aws_secret_access_key: "<you secret>"
107+
role: ""
108+
```
109+
110+
This secret needs to be referenced in the acitonset.
85111
86112
### Create Blueprint
87113
@@ -97,6 +123,12 @@ So as you can see we will have to create a blueprint depending on how are we goi
97123

98124
Use `rds-postgres-snap-blueprint.yaml` or `rds-postgres-blueprint.yaml` Blueprint if you want to take backup using RDS snapshots or you can use `rds-postgres-dump-blueprint.yaml` Blueprint if you want to extract postgres dump from snapshot and push to S3 storage
99125

126+
**NOTE:**
127+
- The `rds-postgres-dump-blueprint.yaml` blueprint demonstrates how to use credentials from the secret.
128+
- The `rds-postgres-snap-blueprint.yaml` blueprint demonstrates how to use credentials from the profile.
129+
130+
To change that you can modify the blueprints using those examples and documentation in https://docs.kanister.io/functions.html#createrdssnapshot
131+
100132

101133
```bash
102134
$ kubectl create -f <blueprint> -n kasten-io
@@ -106,40 +138,57 @@ $ kubectl create -f <blueprint> -n kasten-io
106138

107139
You can now take a snapshot of the PostgreSQL RDS instance data using an ActionSet defining backup for this application. Create an ActionSet in the same namespace as the controller.
108140

109-
> If you have deployed your application which uses RDS instance in namespace other than `pgtestrds`, you need to modify the commands used below to use the correct namespace
141+
Get profile:
110142

111143
```bash
112144
$ kubectl get profile -n pgtestrds
113145
NAME AGE
114146
s3-profile-sph7s 2h
147+
```
115148

149+
Create actionset file:
150+
151+
> Use correct blueprint name (one of `rds-postgres-dump-bp` or `rds-postgres-snapshot-bp`) you have created earlier
152+
> If you have deployed your application which uses RDS instance in namespace other than `pgtestrds`, you need to modify the commands used below to use the correct namespace
153+
> Please make sure `region` option corresponds to the AWS region where your RDS is deployed.
154+
155+
```yaml
156+
apiVersion: cr.kanister.io/v1alpha1
157+
kind: ActionSet
158+
metadata:
159+
name: rds-backup
160+
namespace: kasten-io
161+
spec:
162+
actions:
163+
- name: backup
164+
blueprint: <blueprint-name>
165+
object:
166+
apiVersion: v1
167+
name: dbconfig
168+
namespace: pgtestrds
169+
resource: configmaps
170+
profile:
171+
name: <your profile>
172+
namespace: pgtestrds
173+
secrets:
174+
aws:
175+
name: rds-secret
176+
namespace: pgtestrds
177+
options:
178+
region: <rds region>
179+
```
180+
181+
Where:
182+
- dbconfig is a configmap holding RDS infromation
183+
Please see pgtest/deploy/config.yaml for configmap format
184+
- rds-secret is an AWS secret with access to RDS resources
116185

117-
# Use correct blueprint name (one of `rds-postgres-dump-bp` or `rds-postgres-snapshot-bp`) you have created earlier
118-
119-
cat <<EOF | kubectl apply -f -
120-
> apiVersion: cr.kanister.io/v1alpha1
121-
> kind: ActionSet
122-
> metadata:
123-
> name: rds-backup
124-
> namespace: kasten-io
125-
> spec:
126-
> actions:
127-
> - name: backup
128-
> blueprint: <blueprint-name>
129-
> object:
130-
> apiVersion: v1
131-
> name: dbconfig
132-
> namespace: pgtestrds
133-
> resource: configmaps
134-
> profile:
135-
> name: s3-profile-sph7s
136-
> namespace: pgtestrds
137-
> EOF
138-
actionset.cr.kanister.io/rds-backup created
139186

140-
# Where,
141-
# dbconfig is a configmap holding RDS infromation
142-
# Please see pgtest/deploy/config.yaml for configmap format
187+
Apply actionset:
188+
189+
```bash
190+
$ kubectl apply -f rds-backup-actionset.yaml
191+
actionset.cr.kanister.io/rds-backup created
143192
144193
# View the status of the actionset
145194
$ kubectl --namespace kasten-io describe actionset rds-backup

examples/aws-rds/postgresql/rds-postgres-dump-blueprint.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ actions:
1717
name: createSnapshot
1818
args:
1919
instanceID: '{{ index .Object.data "postgres.instanceid" }}'
20+
credentialsSource: secret
21+
credentialsSecret: aws
22+
region: '{{ .Options.region }}'
2023
- func: ExportRDSSnapshotToLocation
2124
name: exportSnapshot
2225
objects:
@@ -35,10 +38,16 @@ actions:
3538
snapshotID: "{{ .Phases.createSnapshot.Output.snapshotID }}"
3639
backupArtifactPrefix: test-postgresql-instance/postgres
3740
dbSubnetGroup: "{{ .Phases.createSnapshot.Output.dbSubnetGroup }}"
41+
credentialsSource: secret
42+
credentialsSecret: aws
43+
region: '{{ .Options.region }}'
3844
- func: DeleteRDSSnapshot
3945
name: deleteSnapshot
4046
args:
4147
snapshotID: "{{ .Phases.createSnapshot.Output.snapshotID }}"
48+
credentialsSource: secret
49+
credentialsSecret: aws
50+
region: '{{ .Options.region }}'
4251
restore:
4352
inputArtifactNames:
4453
- backupInfo
@@ -60,6 +69,9 @@ actions:
6069
password: '{{ index .Phases.restoreSnapshots.Secrets.dbsecret.Data "password" | toString }}'
6170
dbEngine: "PostgreSQL"
6271
dbSubnetGroup: "{{ .ArtifactsIn.backupInfo.KeyValue.dbSubnetGroup }}"
72+
credentialsSource: secret
73+
credentialsSecret: aws
74+
region: '{{ .Options.region }}'
6375
delete:
6476
phases:
6577
- func: KubeTask

pkg/function/create_rds_snapshot.go

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -74,17 +74,12 @@ func (*createRDSSnapshotFunc) Name() string {
7474
return CreateRDSSnapshotFuncName
7575
}
7676

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

84-
// Get aws config from profile
85-
awsConfig, region, err := getAWSConfigFromProfile(ctx, profile)
80+
awsConfig, region, err := getAwsConfig(ctx, credentialsSource, tp)
8681
if err != nil {
87-
return nil, errkit.Wrap(err, "Failed to get AWS creds from profile")
82+
return nil, errkit.Wrap(err, "Failed to get AWS creds")
8883
}
8984

9085
// Create rds client
@@ -185,7 +180,12 @@ func (crs *createRDSSnapshotFunc) Exec(ctx context.Context, tp param.TemplatePar
185180
return nil, err
186181
}
187182

188-
return createRDSSnapshot(ctx, instanceID, dbEngine, tp.Profile)
183+
credentialsSource, err := parseCredentialsSource(args)
184+
if err != nil {
185+
return nil, err
186+
}
187+
188+
return createRDSSnapshot(ctx, instanceID, dbEngine, *credentialsSource, tp)
189189
}
190190

191191
func (*createRDSSnapshotFunc) RequiredArgs() []string {
@@ -198,6 +198,9 @@ func (crs *createRDSSnapshotFunc) Arguments() []string {
198198
return []string{
199199
CreateRDSSnapshotInstanceIDArg,
200200
CreateRDSSnapshotDBEngine,
201+
CredentialsSourceArg,
202+
CredentialsSecretArg,
203+
RegionArg,
201204
}
202205
}
203206

pkg/function/delete_rds_snapshot.go

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -55,16 +55,11 @@ func (*deleteRDSSnapshotFunc) Name() string {
5555
return DeleteRDSSnapshotFuncName
5656
}
5757

58-
func deleteRDSSnapshot(ctx context.Context, snapshotID string, profile *param.Profile, dbEngine RDSDBEngine) error {
59-
// Validate profile
60-
if err := ValidateProfile(profile); err != nil {
61-
return errkit.Wrap(err, "Profile Validation failed")
62-
}
63-
58+
func deleteRDSSnapshot(ctx context.Context, snapshotID string, credentialsSource awsCredentialsSource, tp param.TemplateParams, dbEngine RDSDBEngine) error {
6459
// Get aws config from profile
65-
awsConfig, region, err := getAWSConfigFromProfile(ctx, profile)
60+
awsConfig, region, err := getAwsConfig(ctx, credentialsSource, tp)
6661
if err != nil {
67-
return errkit.Wrap(err, "Failed to get AWS creds from profile")
62+
return errkit.Wrap(err, "Failed to get AWS creds")
6863
}
6964

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

133-
return nil, deleteRDSSnapshot(ctx, snapshotID, tp.Profile, dbEngine)
128+
credentialsSource, err := parseCredentialsSource(args)
129+
if err != nil {
130+
return nil, err
131+
}
132+
133+
return nil, deleteRDSSnapshot(ctx, snapshotID, *credentialsSource, tp, dbEngine)
134134
}
135135

136136
func (*deleteRDSSnapshotFunc) RequiredArgs() []string {
@@ -141,6 +141,9 @@ func (*deleteRDSSnapshotFunc) Arguments() []string {
141141
return []string{
142142
DeleteRDSSnapshotSnapshotIDArg,
143143
CreateRDSSnapshotDBEngine,
144+
CredentialsSourceArg,
145+
CredentialsSecretArg,
146+
RegionArg,
144147
}
145148
}
146149

0 commit comments

Comments
 (0)