Skip to content

Commit cf23fef

Browse files
committed
Vault copy perms; disable lifecycle update; AWS Backup security
- Adds vault access policy statements limiting copying from the sample vauts. Only one intended next vault is acceptable. - Allows separate disabling of the function to reduce retention of original backups after they have been copied. - Addresses, in the ReadMe, a security limitation of AWS Backup.
1 parent e2e51cc commit cf23fef

2 files changed

Lines changed: 110 additions & 40 deletions

File tree

README.md

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -268,12 +268,24 @@ software at your own risk. You are encouraged to evaluate the source code._
268268

269269
- Least-privilege roles for the AWS Lambda functions
270270

271+
- The role for the function that reduces retention of original backups after
272+
they have been copied can access backups in any vault in the same AWS
273+
account and region. Tampering with the function's source code or
274+
environment variables would allow switching vaults. The backup AWS
275+
account acts as a security barrier; the function and its role are never
276+
created there. (Issue: backup or `recoveryPoint`
277+
[ARNs](https://docs.aws.amazon.com/service-authorization/latest/reference/list_awsbackup.html#awsbackup-resources-for-iam-policies),
278+
do not include the vault name, and there is no
279+
[condition key](https://docs.aws.amazon.com/service-authorization/latest/reference/list_awsbackup.html#awsbackup-policy-keys)
280+
such as backup:VaultARN.)
281+
271282
- Readable IAM policies, formatted as CloudFormation YAML rather than JSON,
272283
and broken down into discrete statements by service, resource or principal
273284

274-
- Tolerance for slow operations and clock drift in a distributed system.
275-
The function to schedule original backups for deletion adds a full-day
276-
margin.
285+
- Tolerance for slow operations and clock drift in a distributed system
286+
287+
- The function that reduces retention of original backups after they have
288+
been copied applies a full-day margin.
277289

278290
- Option to encrypt logs and queued event errors at rest, using the AWS Key
279291
Management System (KMS)
@@ -362,10 +374,14 @@ remember wishing for a simpler, self-documenting function.
362374
So, Paul decided to write a new solution from scratch, on his own behalf. The
363375
benefits?
364376

365-
- One CloudFormation template replaces three, so that advanced users can also
366-
use it to create a StackSet for deployment at scale. Whether the current AWS
367-
account and region match the backup account and backup region determines
368-
which AWS resources are created, and what the source and target strings are.
377+
- One CloudFormation template replaces AWS's three templates. Advanced
378+
users can use the template to create a StackSet for deployment at scale.
379+
Whether the current AWS account and region match the backup account and
380+
backup region determines which AWS resources are created, and what the
381+
source and target strings are.
382+
383+
- On-demand backups are supported. AWS's solution depends on a copy step
384+
that can be included in backup plans but not in on-demand backup requests.
369385

370386
- Advanced users can provide a multi-region KMS key. For now, Paul is not
371387
publishing his test key definitions and key policies. The risk that an LLM

backup_events_aws.yaml

Lines changed: 87 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,24 @@ Parameters:
2020
Type: String
2121
Default: "github.com/sqlxpert/backup-events-aws"
2222

23-
Enable:
23+
EnableCopy:
2424
Type: String
2525
Description: >-
26-
No catch-up feature! Backups completed while this is false will not be
27-
copied to the backup account, even after the setting is toggled back to
28-
true. Copies completed while this is false will not be copied to the
29-
backup region, even after the setting is toggled back to true.
26+
No catch-up feature! Backups completed while this is false will never be
27+
copied to the backup account. Copies completed while this is false will
28+
never be copied to the backup region.
29+
Default: "true"
30+
AllowedValues:
31+
- "false"
32+
- "true"
33+
34+
EnableUpdateLifecycle:
35+
Type: String
36+
Description: >-
37+
No catch-up feature! Backups completed while this is false will never
38+
have their lifecycles updated for early deletion. 3 copies (2 copies in
39+
the backup account, plus the original backup) will be retained according
40+
to the backup's initial lifecycle.
3041
Default: "true"
3142
AllowedValues:
3243
- "false"
@@ -236,7 +247,8 @@ Metadata:
236247

237248
- Label: { default: Essential }
238249
Parameters:
239-
- Enable
250+
- EnableCopy
251+
- EnableUpdateLifecycle
240252
- OrgId
241253
- BackupAccountId
242254
- BackupRegion
@@ -282,8 +294,10 @@ Metadata:
282294
PlaceholderHelp:
283295
default: For help, see
284296

285-
Enable:
286-
default: Enabled?
297+
EnableCopy:
298+
default: Enable copying of backups
299+
EnableUpdateLifecycle:
300+
default: Enable backup retention reduction
287301
OrgId:
288302
default: AWS Organization ID
289303
BackupAccountId:
@@ -339,20 +353,28 @@ Rules:
339353
AssertDescription: >-
340354
BackupRegion and BackupRegionAlternate must be different.
341355
356+
EnableUpdateLifecycleRequiresEnableCopy:
357+
Assertions:
358+
- Assert:
359+
Fn::Not:
360+
- Fn::And:
361+
- !Equals [ !Ref EnableUpdateLifecycle, "true" ]
362+
- !Not [ !Equals [ !Ref EnableCopy, "true" ] ]
363+
AssertDescription: >-
364+
EnableUpdateLifecycle requires EnableCopy.
365+
342366
Conditions:
343367

344-
EnableTrue: !Equals [ !Ref Enable, "true" ]
368+
EnableCopyTrue: !Equals [ !Ref EnableCopy, "true" ]
369+
EnableUpdateLifecycleTrue: !Equals [ !Ref EnableUpdateLifecycle, "true" ]
345370

346371
InBackupRegion: !Equals [ !Ref AWS::Region, !Ref BackupRegion ]
347372

348373
InBackupAccount: !Equals [ !Ref AWS::AccountId, !Ref BackupAccountId ]
349374
NotInBackupAccount: !Not [ !Condition InBackupAccount ]
350375

351376
CreateSampleVaultTrue: !Equals [ !Ref CreateSampleVault, "true" ]
352-
353377
VaultCustomKmsKeyNo: !Equals [ !Ref VaultCustomKmsKey, "" ]
354-
InBackupAccountAndVaultCustomKmsKeyNo:
355-
!And [ !Condition InBackupAccount, !Condition VaultCustomKmsKeyNo ]
356378

357379
OnlyResourceAccountIdBlank: !Equals [ !Ref OnlyResourceAccountId, "" ]
358380

@@ -579,24 +601,38 @@ Resources:
579601
BackupVaultTags:
580602
Note:
581603
Fn::If:
582-
- InBackupAccountAndVaultCustomKmsKeyNo
583-
- >-
584-
Only for copies of copies of EFS backups.
585-
Prior copy: same account and other region and encrypted with
586-
the AWS-managed default aws/backup key for that region.
587-
This copy: encrypted with the aws/backup key for this region.
588-
- >-
589-
Only for copies of EFS backups.
590-
Original backup: other account and same region and
591-
unencrypted.
592-
This copy: encrypted with the AWS-managed default aws/backup
593-
key for this account and this region.
604+
- VaultCustomKmsKeyNo
605+
- Fn::If:
606+
- InBackupAccount
607+
- Fn::If:
608+
- InBackupRegion
609+
- >-
610+
Only for copies of copies of EFS backups.
611+
Prior copy: same account and other region and
612+
encrypted with the AWS-managed default aws/backup key
613+
for that region.
614+
This copy: encrypted with the aws/backup key for this
615+
region.
616+
- >-
617+
Only for copies of EFS backups.
618+
Original backup: other account and same region and
619+
unencrypted.
620+
This copy: encrypted with the AWS-managed default
621+
aws/backup key for this account and this region.
622+
- >-
623+
Only for backups of unencrypted EFS file systems.
624+
File system: same account and region and unencrypted.
625+
This backup: encrypted with the aws/backup key for this
626+
region.
627+
- !Ref AWS::NoValue
594628
AccessPolicy:
595-
Fn::If:
596-
- InBackupAccount
597-
- Version: "2012-10-17"
598-
Statement:
599-
- Effect: Allow
629+
Version: "2012-10-17"
630+
Statement:
631+
632+
- Fn::If:
633+
- InBackupAccount
634+
- Sid: CopyIntoBackupVaultAllowServiceRole
635+
Effect: Allow
600636
Principal: "*"
601637
Condition:
602638
StringEquals:
@@ -605,7 +641,24 @@ Resources:
605641
"aws:PrincipalArn": !Sub "arn:aws:iam::*:role/${CopyRoleName}"
606642
Action: backup:CopyIntoBackupVault
607643
Resource: "*"
608-
- !Ref AWS::NoValue
644+
- !Ref AWS::NoValue
645+
646+
- Sid: CopyFromBackupVaultExclusiveCopyTarget
647+
Effect: Deny
648+
Principal: "*"
649+
Action: backup:CopyFromBackupVault
650+
Resource: "*"
651+
Condition:
652+
"ForAllValues:ArnNotEquals":
653+
"backup:CopyTargets":
654+
# See also VaultARN and VAULT_ARN
655+
- Fn::If:
656+
- InBackupAccount
657+
- Fn::If:
658+
- InBackupRegion
659+
- !Sub "arn:${AWS::Partition}:backup:${BackupRegionAlternate}:${AWS::AccountId}:backup-vault:${VaultName}"
660+
- !Sub "arn:${AWS::Partition}:backup:${BackupRegion}:${AWS::AccountId}:backup-vault:${VaultName}"
661+
- !Sub "arn:${AWS::Partition}:backup:${AWS::Region}:${BackupAccountId}:backup-vault:${VaultName}"
609662

610663
EventTargetErrorQueue:
611664
Type: AWS::SQS::Queue
@@ -670,7 +723,7 @@ Resources:
670723
- Id: !Ref CopyLambdaFn
671724
Arn: !GetAtt CopyLambdaFn.Arn
672725
DeadLetterConfig: { Arn: !GetAtt EventTargetErrorQueue.Arn }
673-
State: !If [ EnableTrue, ENABLED, DISABLED ]
726+
State: !If [ EnableCopyTrue, ENABLED, DISABLED ]
674727

675728
Copy1ToBackupAcctCompletedCopyLambdaFnEvRule:
676729
Type: AWS::Events::Rule
@@ -698,7 +751,7 @@ Resources:
698751
RoleArn: !GetAtt InvokeCopyLambdaFnInBackupAcctRole.Arn
699752
Arn: !Sub "arn:${AWS::Partition}:lambda:${AWS::Region}:${BackupAccountId}:function:${UniqueNamePrefix}-CopyLambdaFn"
700753
DeadLetterConfig: { Arn: !GetAtt EventTargetErrorQueue.Arn }
701-
State: !If [ EnableTrue, ENABLED, DISABLED ]
754+
State: !If [ EnableCopyTrue, ENABLED, DISABLED ]
702755

703756
# Administrator: Block other invocations
704757
BackupCompletedCopyLambdaFnEvRulePerm:
@@ -755,7 +808,7 @@ Resources:
755808
- Id: !Ref UpdateLifecycleLambdaFn
756809
Arn: !GetAtt UpdateLifecycleLambdaFn.Arn
757810
DeadLetterConfig: { Arn: !GetAtt EventTargetErrorQueue.Arn }
758-
State: !If [ EnableTrue, ENABLED, DISABLED ]
811+
State: !If [ EnableUpdateLifecycleTrue, ENABLED, DISABLED ]
759812

760813
# Administrator: Block other invocations
761814
UpdateLifecycleLambdaFnPerm:
@@ -795,6 +848,7 @@ Resources:
795848
COPY_ROLE_ARN: !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/${CopyRoleName}"
796849
BACKUP_VAULT_NAME: !Ref VaultName
797850
DESTINATION_BACKUP_VAULT_ARN:
851+
# See also VaultARN and backup:CopyTargets
798852
Fn::If:
799853
- InBackupAccount
800854
- Fn::If:

0 commit comments

Comments
 (0)