-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #33 from k9securityio/feat-generate-ddb-resource-p…
…olicies feat: Generate DynamoDB resource policies
- Loading branch information
Showing
10 changed files
with
597 additions
and
53 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,6 +8,7 @@ Supported services: | |
|
||
* S3 | ||
* KMS | ||
* DynamoDB | ||
|
||
This library [simplifies IAM as described in Effective IAM for AWS](https://www.effectiveiam.com/simplify-aws-iam) and is fully-supported by k9 Security. We're happy to answer questions or help you integrate it via a [GitHub issue](https://github.com/k9securityio/k9-cdk/issues) or email to [[email protected]](mailto:[email protected]?subject=k9-cdk). | ||
|
||
|
@@ -34,7 +35,8 @@ const administerResourceArns = [ | |
]; | ||
|
||
const readConfigArns = administerResourceArns.concat([ | ||
"arn:aws:iam::123456789012:role/k9-auditor" | ||
"arn:aws:iam::123456789012:role/k9-auditor", | ||
"arn:aws:iam::123456789012:role/aws-service-role/access-analyzer.amazonaws.com/AWSServiceRoleForAccessAnalyzer" | ||
]); | ||
|
||
const app = new cdk.App(); | ||
|
@@ -93,20 +95,40 @@ new kms.Key(stack, 'KMSKey', { | |
}); | ||
``` | ||
|
||
The example stack demonstrates full use of the k9 S3 and KMS policy generators. Generated policies: | ||
Protecting a DynamoDB table follows the same path as KMS, generating a policy then providing it to the DynamoDB table construct via props: | ||
|
||
```typescript | ||
import * as dynamodb from "aws-cdk-lib/aws-dynamodb"; | ||
|
||
const ddbResourcePolicyProps: k9.dynamodb.K9DynamoDBResourcePolicyProps = { | ||
k9DesiredAccess: k9BucketPolicyProps.k9DesiredAccess | ||
}; | ||
|
||
|
||
const ddbResourcePolicy = k9.dynamodb.makeResourcePolicy(ddbResourcePolicyProps); | ||
|
||
const table = new dynamodb.TableV2(stack, 'app-table-with-k9-policy', { | ||
partitionKey: { name: 'pk', type: dynamodb.AttributeType.STRING }, | ||
resourcePolicy: ddbResourcePolicy, | ||
}); | ||
``` | ||
|
||
The example stack demonstrates full use of the k9 S3, KMS, and DynamoDB policy generators. Generated policies: | ||
|
||
S3 Bucket Policy: | ||
|
||
* [Templatized Bucket Policy](examples/generated.bucket-policy.json) | ||
* [BucketPolicy resource in CFn template](examples/K9Example.template.json) | ||
|
||
KMS Key Policy: | ||
|
||
* [Templatized Key Policy](examples/generated.key-policy.json) | ||
* [KeyPolicy attribute of Key resource in CFn template](examples/K9Example.template.json) | ||
|
||
## Specialized Use Cases | ||
|
||
k9-cdk can be configured to support specialized use cases, including: | ||
* [Public Bucket](docs/use-case-public-bucket.md) - Publicaly readable objects, least privilege for all other actions | ||
* [Public Bucket](docs/use-case-public-bucket.md) - Publicly readable objects, least privilege for all other actions | ||
|
||
## Local Development and Testing | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
import { AccountRootPrincipal, Effect, PolicyDocument, PolicyStatement } from 'aws-cdk-lib/aws-iam'; | ||
import * as iam from 'aws-cdk-lib/aws-iam'; | ||
import { | ||
AccessCapability, | ||
canPrincipalsManageResources, | ||
getAccessCapabilityFromValue, | ||
IAccessSpec, | ||
K9PolicyFactory, | ||
} from './k9policy'; | ||
|
||
|
||
export interface K9DynamoDBResourcePolicyProps { | ||
readonly k9DesiredAccess: Array<IAccessSpec>; | ||
} | ||
|
||
let SUPPORTED_CAPABILITIES = new Array<AccessCapability>( | ||
AccessCapability.ADMINISTER_RESOURCE, | ||
AccessCapability.READ_CONFIG, | ||
AccessCapability.READ_DATA, | ||
AccessCapability.WRITE_DATA, | ||
AccessCapability.DELETE_DATA, | ||
); | ||
|
||
export const SID_DENY_EVERYONE_ELSE = 'DenyEveryoneElse'; | ||
|
||
/** | ||
* Generate a DynamoDB resource policy from the provided props that can be attached to DynamoDB | ||
* resources, particularly tables & indices. | ||
* | ||
* @param props specifying desired access | ||
* @return a PolicyDocument that can be attached to DynamoDB resources | ||
*/ | ||
export function makeResourcePolicy(props: K9DynamoDBResourcePolicyProps): PolicyDocument { | ||
const policyFactory = new K9PolicyFactory(); | ||
const policy = new iam.PolicyDocument(); | ||
|
||
const resourceArns = ['*']; | ||
|
||
let accessSpecsByCapabilityRecs = policyFactory.mergeDesiredAccessSpecsByCapability(SUPPORTED_CAPABILITIES, props.k9DesiredAccess); | ||
let accessSpecsByCapability: Map<AccessCapability, IAccessSpec> = new Map(); | ||
|
||
for (let [capabilityStr, accessSpec] of Object.entries(accessSpecsByCapabilityRecs)) { | ||
accessSpecsByCapability.set(getAccessCapabilityFromValue(capabilityStr), accessSpec); | ||
} | ||
|
||
if (!canPrincipalsManageResources(accessSpecsByCapability)) { | ||
throw Error('At least one principal must be able to administer and read-config for DynamoDB resources' + | ||
' so data data remains accessible; found:\n' + | ||
`administer-resource: '${accessSpecsByCapability.get(AccessCapability.ADMINISTER_RESOURCE)?.allowPrincipalArns}'\n` + | ||
`read-config: '${accessSpecsByCapability.get(AccessCapability.READ_CONFIG)?.allowPrincipalArns}'`, | ||
); | ||
} | ||
|
||
const allowStatements = policyFactory.makeAllowStatements('DynamoDB', | ||
SUPPORTED_CAPABILITIES, | ||
Array.from(accessSpecsByCapability.values()), | ||
resourceArns, | ||
true); | ||
policy.addStatements(...allowStatements); | ||
|
||
const denyEveryoneElseStatement = new PolicyStatement({ | ||
sid: SID_DENY_EVERYONE_ELSE, | ||
effect: Effect.DENY, | ||
principals: policyFactory.makeDenyEveryoneElsePrincipals(), | ||
actions: ['dynamodb:*'], | ||
resources: resourceArns, | ||
}); | ||
denyEveryoneElseStatement.addCondition('Bool', { | ||
'aws:PrincipalIsAWSService': ['false'], | ||
}); | ||
const denyEveryoneElseTest = policyFactory.wasLikeUsed(props.k9DesiredAccess) ? | ||
'ArnNotLike' : | ||
'ArnNotEquals'; | ||
const allAllowedPrincipalArns = policyFactory.getAllowedPrincipalArns(props.k9DesiredAccess); | ||
const accountRootPrincipal = new AccountRootPrincipal(); | ||
denyEveryoneElseStatement.addCondition(denyEveryoneElseTest, { | ||
'aws:PrincipalArn': [ | ||
// Place Root Principal arn in stable, prominent position; | ||
// will render as an object Fn::Join'ing Partition & AccountId | ||
accountRootPrincipal.arn, | ||
...allAllowedPrincipalArns, | ||
], | ||
}); | ||
|
||
policy.addStatements( | ||
denyEveryoneElseStatement, | ||
); | ||
|
||
policy.validateForResourcePolicy(); | ||
|
||
return policy; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
export * as k9policy from './k9policy'; | ||
export * as dynamodb from './dynamodb'; | ||
export * as kms from './kms'; | ||
export * as s3 from './s3'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.