-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor(GuLogShippingPolicy): make GuLogShippingPolicy a singleton (#…
…337) The policy `GuLogShippingPolicy` is now a [singleton](https://en.wikipedia.org/wiki/Singleton_pattern) as we only ever want one per stack. If there are multiple roles defined in this stack that require log shipping permissions, a single policy will be defined and attached to the roles. This DRYness helps keep within the file size limits of cloudformation too. Also included in this change is a new `GuLoggingStreamNameParameter`, also written as a singleton for the same reasons. Usage hasn't really changed as this policy will never really be used by consumer stacks as they'l be using `GuInstanceRole` instead, which adds this policy by default. BREAKING CHANGE: * The API for `GuLogShippingPolicy` has changed. It is now a singleton and direct instantiation is not possible.
- Loading branch information
Showing
6 changed files
with
253 additions
and
62 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 |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import type { GuStack } from "../stack"; | ||
import { GuStringParameter } from "./base"; | ||
|
||
export class GuLoggingStreamNameParameter extends GuStringParameter { | ||
private static instance: GuStringParameter | undefined; | ||
|
||
// eslint-disable-next-line custom-rules/valid-constructors -- TODO be better | ||
private constructor(scope: GuStack) { | ||
super(scope, "LoggingStreamName", { | ||
description: "SSM parameter containing the Name (not ARN) on the kinesis stream", | ||
default: "/account/services/logging.stream.name", | ||
fromSSM: true, | ||
}); | ||
} | ||
|
||
public static getInstance(stack: GuStack): GuLoggingStreamNameParameter { | ||
// Resources can only live in the same App so return a new `GuSSMRunCommandPolicy` where necessary. | ||
// See https://github.com/aws/aws-cdk/blob/0ea4b19afd639541e5f1d7c1783032ee480c307e/packages/%40aws-cdk/core/lib/private/refs.ts#L47-L50 | ||
const isSameStack = this.instance?.node.root === stack.node.root; | ||
|
||
if (!this.instance || !isSameStack) { | ||
this.instance = new GuLoggingStreamNameParameter(stack); | ||
} | ||
|
||
return this.instance; | ||
} | ||
} |
163 changes: 163 additions & 0 deletions
163
src/constructs/iam/policies/__snapshots__/log-shipping.test.ts.snap
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,163 @@ | ||
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`The GuLogShippingPolicy singleton class will only be defined once in a stack, even when attached to multiple roles 1`] = ` | ||
Object { | ||
"Parameters": Object { | ||
"LoggingStreamName": Object { | ||
"Default": "/account/services/logging.stream.name", | ||
"Description": "SSM parameter containing the Name (not ARN) on the kinesis stream", | ||
"Type": "AWS::SSM::Parameter::Value<String>", | ||
}, | ||
"Stage": Object { | ||
"AllowedValues": Array [ | ||
"CODE", | ||
"PROD", | ||
], | ||
"Default": "CODE", | ||
"Description": "Stage name", | ||
"Type": "String", | ||
}, | ||
}, | ||
"Resources": Object { | ||
"GuLogShippingPolicy981BFE5A": Object { | ||
"Properties": Object { | ||
"PolicyDocument": Object { | ||
"Statement": Array [ | ||
Object { | ||
"Action": Array [ | ||
"kinesis:Describe*", | ||
"kinesis:Put*", | ||
], | ||
"Effect": "Allow", | ||
"Resource": Object { | ||
"Fn::Join": Array [ | ||
"", | ||
Array [ | ||
"arn:aws:kinesis:", | ||
Object { | ||
"Ref": "AWS::Region", | ||
}, | ||
":", | ||
Object { | ||
"Ref": "AWS::AccountId", | ||
}, | ||
":stream/", | ||
Object { | ||
"Ref": "LoggingStreamName", | ||
}, | ||
], | ||
], | ||
}, | ||
}, | ||
], | ||
"Version": "2012-10-17", | ||
}, | ||
"PolicyName": "GuLogShippingPolicy981BFE5A", | ||
"Roles": Array [ | ||
Object { | ||
"Ref": "MyFirstRoleAF66ED75", | ||
}, | ||
Object { | ||
"Ref": "MySecondRoleB9F57405", | ||
}, | ||
], | ||
}, | ||
"Type": "AWS::IAM::Policy", | ||
}, | ||
"MyFirstRoleAF66ED75": Object { | ||
"Properties": Object { | ||
"AssumeRolePolicyDocument": Object { | ||
"Statement": Array [ | ||
Object { | ||
"Action": "sts:AssumeRole", | ||
"Effect": "Allow", | ||
"Principal": Object { | ||
"Service": Object { | ||
"Fn::Join": Array [ | ||
"", | ||
Array [ | ||
"ec2.", | ||
Object { | ||
"Ref": "AWS::URLSuffix", | ||
}, | ||
], | ||
], | ||
}, | ||
}, | ||
}, | ||
], | ||
"Version": "2012-10-17", | ||
}, | ||
"Tags": Array [ | ||
Object { | ||
"Key": "App", | ||
"Value": "testing", | ||
}, | ||
Object { | ||
"Key": "gu:cdk:version", | ||
"Value": "TEST", | ||
}, | ||
Object { | ||
"Key": "Stack", | ||
"Value": "test-stack", | ||
}, | ||
Object { | ||
"Key": "Stage", | ||
"Value": Object { | ||
"Ref": "Stage", | ||
}, | ||
}, | ||
], | ||
}, | ||
"Type": "AWS::IAM::Role", | ||
}, | ||
"MySecondRoleB9F57405": Object { | ||
"Properties": Object { | ||
"AssumeRolePolicyDocument": Object { | ||
"Statement": Array [ | ||
Object { | ||
"Action": "sts:AssumeRole", | ||
"Effect": "Allow", | ||
"Principal": Object { | ||
"Service": Object { | ||
"Fn::Join": Array [ | ||
"", | ||
Array [ | ||
"ec2.", | ||
Object { | ||
"Ref": "AWS::URLSuffix", | ||
}, | ||
], | ||
], | ||
}, | ||
}, | ||
}, | ||
], | ||
"Version": "2012-10-17", | ||
}, | ||
"Tags": Array [ | ||
Object { | ||
"Key": "App", | ||
"Value": "testing", | ||
}, | ||
Object { | ||
"Key": "gu:cdk:version", | ||
"Value": "TEST", | ||
}, | ||
Object { | ||
"Key": "Stack", | ||
"Value": "test-stack", | ||
}, | ||
Object { | ||
"Key": "Stage", | ||
"Value": Object { | ||
"Ref": "Stage", | ||
}, | ||
}, | ||
], | ||
}, | ||
"Type": "AWS::IAM::Role", | ||
}, | ||
}, | ||
} | ||
`; |
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 |
---|---|---|
@@ -1,25 +1,31 @@ | ||
import { Effect, PolicyStatement } from "@aws-cdk/aws-iam"; | ||
import type { GuStack } from "../../core"; | ||
import { GuStringParameter } from "../../core"; | ||
import type { GuPolicyProps } from "./base-policy"; | ||
import { GuPolicy } from "./base-policy"; | ||
import { GuLoggingStreamNameParameter } from "../../core/parameters/log-shipping"; | ||
import { GuAllowPolicy } from "./base-policy"; | ||
|
||
export class GuLogShippingPolicy extends GuPolicy { | ||
constructor(scope: GuStack, id: string = "GuLogShippingPolicy", props?: GuPolicyProps) { | ||
super(scope, id, { ...props }); | ||
export class GuLogShippingPolicy extends GuAllowPolicy { | ||
private static instance: GuLogShippingPolicy | undefined; | ||
|
||
const loggingStreamNameParam = new GuStringParameter(scope, "LoggingStreamName", { | ||
description: "SSM parameter containing the Name (not ARN) on the kinesis stream", | ||
default: "/account/services/logging.stream.name", | ||
fromSSM: true, | ||
// eslint-disable-next-line custom-rules/valid-constructors -- TODO be better | ||
private constructor(scope: GuStack) { | ||
super(scope, "GuLogShippingPolicy", { | ||
actions: ["kinesis:Describe*", "kinesis:Put*"], | ||
resources: [ | ||
`arn:aws:kinesis:${scope.region}:${scope.account}:stream/${ | ||
GuLoggingStreamNameParameter.getInstance(scope).valueAsString | ||
}`, | ||
], | ||
}); | ||
} | ||
|
||
public static getInstance(stack: GuStack): GuLogShippingPolicy { | ||
// Resources can only live in the same App so return a new `GuSSMRunCommandPolicy` where necessary. | ||
// See https://github.com/aws/aws-cdk/blob/0ea4b19afd639541e5f1d7c1783032ee480c307e/packages/%40aws-cdk/core/lib/private/refs.ts#L47-L50 | ||
const isSameStack = this.instance?.node.root === stack.node.root; | ||
|
||
if (!this.instance || !isSameStack) { | ||
this.instance = new GuLogShippingPolicy(stack); | ||
} | ||
|
||
this.addStatements( | ||
new PolicyStatement({ | ||
effect: Effect.ALLOW, | ||
actions: ["kinesis:Describe*", "kinesis:Put*"], | ||
resources: [`arn:aws:kinesis:${scope.region}:${scope.account}:stream/${loggingStreamNameParam.valueAsString}`], | ||
}) | ||
); | ||
return this.instance; | ||
} | ||
} |
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