Skip to content
This repository has been archived by the owner on Dec 6, 2024. It is now read-only.

Commit

Permalink
feat: enable flow logs for network monitoring (#883)
Browse files Browse the repository at this point in the history
* feat: enable flow logs for network monitoring
  • Loading branch information
SanketD92 authored Jan 26, 2022
1 parent fa2550c commit a36702b
Show file tree
Hide file tree
Showing 10 changed files with 130 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ Parameters:
AllowedValues: [true, false]
Description: Onboard this account to support AppStream

EnableFlowLogs:
Type: String
AllowedValues: [true, false]
Description: Enable flow logs on VPCs and Subnets created on this account

Namespace:
Type: String
Description: An environment name that will be prefixed to resource names
Expand Down Expand Up @@ -122,15 +127,20 @@ Metadata:
- VpcCidr
- PublicSubnetCidr

# Resources linked to AppStream conditions are evaluated further prior to getting sent to CloudFormation
# Take a look at addons/addon-base-raas/packages/base-raas-services/lib/cfn-templates/cfn-template-service.getTemplate()
Conditions:
isAppStream: !Equals
- !Ref EnableAppStream
- true
isNotAppStream: !Not [Condition: isAppStream]
hasCustomDomain: !Not [!Equals [!Ref "DomainName", ""]]
hasCustomDomain: !Not [!Equals [!Ref 'DomainName', '']]
isAppStreamAndCustomDomain: !And
- !Not [!Equals [!Ref "DomainName", ""]]
- !Not [!Equals [!Ref 'DomainName', '']]
- !Condition isAppStream
enableFlowLogs: !Equals [!Ref EnableFlowLogs, true]
enableFlowLogsNonAppStream: !And [Condition: isNotAppStream,Condition: enableFlowLogs]
enableFlowLogsWithAppStream: !And [Condition: isAppStream,Condition: enableFlowLogs]

Resources:
Route53HostedZone:
Expand All @@ -140,7 +150,7 @@ Resources:
Name: !Ref DomainName
VPCs:
- VPCId: !Ref VPC
VPCRegion: !Ref "AWS::Region"
VPCRegion: !Ref 'AWS::Region'

# A role used for launching environments using AWS Service Catalog
# This is the role that code (ApiHandlerLambda and WorkflowLoopRunnerLambda) in central account
Expand Down Expand Up @@ -266,6 +276,17 @@ Resources:
Resource:
- !Sub 'arn:${AWS::Partition}:iam::${AWS::AccountId}:role/${LaunchConstraintRolePrefix}LaunchConstraint'
- !Sub 'arn:${AWS::Partition}:iam::${AWS::AccountId}:role/*presigned-url-sagemaker-notebook-role'
- PolicyName: cloudwatch-access-policy
PolicyDocument:
Statement:
Effect: Allow
Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
Resource:
- !Sub 'arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:${Namespace}-*:*'
- !Sub 'arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:${Namespace}-*:log-stream:*'
- !If
- isAppStreamAndCustomDomain
- PolicyName: route53-access
Expand Down Expand Up @@ -302,6 +323,14 @@ Resources:
- servicecatalog:*
- ec2-instance-connect:*
Resource: '*'
- Effect: Allow
Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
Resource:
- !Sub 'arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:${Namespace}-*:*'
- !Sub 'arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:${Namespace}-*:log-stream:*'
- Effect: Allow
Action:
- iam:PassRole
Expand Down Expand Up @@ -603,6 +632,22 @@ Resources:
- Key: Name
Value: !Sub ${Namespace} vpc

FlowLogVPC:
Type: AWS::EC2::FlowLog
Condition: enableFlowLogs
Properties:
ResourceId: !Ref VPC
ResourceType: VPC
TrafficType: ACCEPT
DeliverLogsPermissionArn: !GetAtt CrossAccountRoleEnvMgmt.Arn
LogGroupName: VPCLogGroup
LogFormat: '${version} ${vpc-id} ${subnet-id} ${instance-id} ${srcaddr} ${dstaddr} ${srcport} ${dstport} ${protocol} ${tcp-flags} ${type} ${pkt-srcaddr} ${pkt-dstaddr}'
Tags:
- Key: Name
Value: FlowLogForVPC
- Key: Purpose
Value: AcceptTraffic

InternetGateway:
Type: AWS::EC2::InternetGateway
Condition: isNotAppStream
Expand All @@ -623,13 +668,29 @@ Resources:
Condition: isNotAppStream
Properties:
VpcId: !Ref VPC
AvailabilityZone: !Select [0, !GetAZs '' ]
AvailabilityZone: !Select [0, !GetAZs '']
CidrBlock: !Ref PublicSubnetCidr
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub ${Namespace} public subnet 1

FlowLogPublicSubnet1:
Type: AWS::EC2::FlowLog
Condition: enableFlowLogsNonAppStream
Properties:
ResourceId: !Ref PublicSubnet1
ResourceType: Subnet
TrafficType: ACCEPT
DeliverLogsPermissionArn: !GetAtt CrossAccountRoleEnvMgmt.Arn
LogGroupName: PublicSubnet1LogGroup
LogFormat: '${version} ${vpc-id} ${subnet-id} ${instance-id} ${srcaddr} ${dstaddr} ${srcport} ${dstport} ${protocol} ${tcp-flags} ${type} ${pkt-srcaddr} ${pkt-dstaddr}'
Tags:
- Key: Name
Value: FlowLogForPublicSubnet1
- Key: Purpose
Value: AcceptTraffic

PublicRouteTable:
Type: AWS::EC2::RouteTable
Condition: isNotAppStream
Expand Down Expand Up @@ -707,6 +768,22 @@ Resources:
- Key: Name
Value: Private AppStream Subnet

FlowLogPrivateAppStreamSubnet:
Type: AWS::EC2::FlowLog
Condition: enableFlowLogsWithAppStream
Properties:
ResourceId: !Ref PrivateAppStreamSubnet
ResourceType: Subnet
TrafficType: ACCEPT
DeliverLogsPermissionArn: !GetAtt CrossAccountRoleEnvMgmt.Arn
LogGroupName: PrivateAppStreamSubnetLogGroup
LogFormat: '${version} ${vpc-id} ${subnet-id} ${instance-id} ${srcaddr} ${dstaddr} ${srcport} ${dstport} ${protocol} ${tcp-flags} ${type} ${pkt-srcaddr} ${pkt-dstaddr}'
Tags:
- Key: Name
Value: FlowLogPrivateAppStreamSubnet
- Key: Purpose
Value: AcceptTraffic

PrivateWorkspaceSubnet:
Type: AWS::EC2::Subnet
Condition: isAppStream
Expand All @@ -719,6 +796,22 @@ Resources:
- Key: Name
Value: Private Workspace Subnet

FlowLogPrivateWorkspaceSubnet:
Type: AWS::EC2::FlowLog
Condition: enableFlowLogsWithAppStream
Properties:
ResourceId: !Ref PrivateWorkspaceSubnet
ResourceType: Subnet
TrafficType: ACCEPT
DeliverLogsPermissionArn: !GetAtt CrossAccountRoleEnvMgmt.Arn
LogGroupName: PrivateWorkspaceSubnetLogGroup
LogFormat: '${version} ${vpc-id} ${subnet-id} ${instance-id} ${srcaddr} ${dstaddr} ${srcport} ${dstport} ${protocol} ${tcp-flags} ${type} ${pkt-srcaddr} ${pkt-dstaddr}'
Tags:
- Key: Name
Value: FlowLogForPrivateWorkspaceSubnet
- Key: Purpose
Value: AcceptTraffic

PrivateWorkspaceRouteTable:
Type: 'AWS::EC2::RouteTable'
Condition: isAppStream
Expand Down Expand Up @@ -898,7 +991,7 @@ Resources:
- !Ref PrivateWorkspaceSubnet
VpcEndpointType: Interface
PrivateDnsEnabled: true
ServiceName: !Sub "com.amazonaws.${AWS::Region}.sagemaker.api"
ServiceName: !Sub 'com.amazonaws.${AWS::Region}.sagemaker.api'
VpcId: !Ref VPC
SecurityGroupIds:
- !Ref SagemakerApiEndpointSecurityGroup
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ describe('AwsAccountService', () => {
'param_AppStreamDisconnectTimeoutSeconds=60&param_AppStreamFleetDesiredInstances=2&' +
'param_AppStreamIdleDisconnectTimeoutSeconds=600&param_AppStreamImageName=&' +
'param_AppStreamInstanceType=&param_AppStreamMaxUserDurationSeconds=86400&' +
'param_EnableAppStream=false&param_DomainName=',
'param_EnableAppStream=false&param_EnableFlowLogs=true&param_DomainName=',
);
});

Expand Down Expand Up @@ -308,7 +308,7 @@ describe('AwsAccountService', () => {
'param_AppStreamDisconnectTimeoutSeconds=60&param_AppStreamFleetDesiredInstances=2&' +
'param_AppStreamIdleDisconnectTimeoutSeconds=600&param_AppStreamImageName=&' +
'param_AppStreamInstanceType=&param_AppStreamMaxUserDurationSeconds=86400&' +
'param_EnableAppStream=false&param_DomainName=testdomain.aws',
'param_EnableAppStream=false&param_EnableFlowLogs=true&param_DomainName=testdomain.aws',
);
expect(awsAccountsService.update).toHaveBeenCalledWith(requestContext, update);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ const settingKeys = {
swbMainAccount: 'mainAcct',
stage: 'envName',
isAppStreamEnabled: 'isAppStreamEnabled',
enableFlowLogs: 'enableFlowLogs',
domainName: 'domainName',
};

Expand Down Expand Up @@ -65,6 +66,7 @@ const getCreateStackUrl = (cfnTemplateInfo, createParams) => {
appStreamInstanceType,
appStreamMaxUserDurationSeconds,
enableAppStream,
enableFlowLogs,
domainName,
} = createParams;
const url = [
Expand All @@ -84,6 +86,7 @@ const getCreateStackUrl = (cfnTemplateInfo, createParams) => {
`&param_AppStreamInstanceType=${appStreamInstanceType || ''}`,
`&param_AppStreamMaxUserDurationSeconds=${appStreamMaxUserDurationSeconds || '86400'}`,
`&param_EnableAppStream=${enableAppStream || 'false'}`,
`&param_EnableFlowLogs=${enableFlowLogs || 'true'}`,
`&param_DomainName=${domainName || ''}`,
].join('');

Expand Down Expand Up @@ -208,6 +211,7 @@ class AwsCfnService extends Service {
createParams.apiHandlerRoleArn = this.settings.get(settingKeys.apiHandlerRoleArn);
createParams.workflowLoopRunnerRoleArn = this.settings.get(settingKeys.workflowLoopRunnerRoleArn);
createParams.enableAppStream = this.settings.get(settingKeys.isAppStreamEnabled);
createParams.enableFlowLogs = this.settings.get(settingKeys.enableFlowLogs);
createParams.domainName = this.settings.optional(settingKeys.domainName, '');
createParams.externalId = account.externalId;
createParams.namespace = cfnTemplateInfo.name;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ class CfnTemplateService extends Service {
let resourceAttributeToDelete = [];
Object.keys(doc.Resources).forEach(resource => {
if (
['isAppStreamAndCustomDomain', 'isAppStream'].includes(
['isAppStreamAndCustomDomain', 'isAppStream', 'enableFlowLogsWithAppStream'].includes(
doc.Resources[resource].Condition && doc.Resources[resource].Condition,
)
) {
Expand All @@ -108,7 +108,7 @@ class CfnTemplateService extends Service {
const outputsToDelete = [];
Object.keys(doc.Outputs).forEach(output => {
if (
['isAppStreamAndCustomDomain', 'isAppStream'].includes(
['isAppStreamAndCustomDomain', 'isAppStream', 'enableFlowLogsWithAppStream'].includes(
doc.Outputs[output].Condition && doc.Outputs[output].Condition,
)
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ describe('ProvisionAccount', () => {
if (key === 'isAppStreamEnabled') {
return false;
}
if (key === 'enableFlowLogs') {
return true;
}
throw new Error('Unexpected key');
},
};
Expand Down Expand Up @@ -174,6 +177,9 @@ describe('ProvisionAccount', () => {
if (key === 'isAppStreamEnabled') {
return 'false';
}
if (key === 'enableFlowLogs') {
return 'true';
}
if (key === 'launchConstraintRolePrefix') {
return '*';
}
Expand Down Expand Up @@ -233,6 +239,9 @@ describe('ProvisionAccount', () => {
if (key === 'isAppStreamEnabled') {
return 'true';
}
if (key === 'enableFlowLogs') {
return 'true';
}
if (key === 'launchConstraintRolePrefix') {
return '*';
}
Expand Down Expand Up @@ -289,6 +298,9 @@ describe('ProvisionAccount', () => {
if (key === 'isAppStreamEnabled') {
return false;
}
if (key === 'enableFlowLogs') {
return true;
}
throw new Error('Unexpected key');
},
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const settingKeys = {
launchConstraintRolePrefix: 'launchConstraintRolePrefix',
launchConstraintPolicyPrefix: 'launchConstraintPolicyPrefix',
isAppStreamEnabled: 'isAppStreamEnabled',
enableFlowLogs: 'enableFlowLogs',
domainName: 'domainName',
};

Expand Down Expand Up @@ -224,6 +225,7 @@ class ProvisionAccount extends StepBase {
addParam('LaunchConstraintRolePrefix', this.settings.get(settingKeys.launchConstraintRolePrefix));
addParam('LaunchConstraintPolicyPrefix', this.settings.get(settingKeys.launchConstraintPolicyPrefix));
addParam('EnableAppStream', this.settings.get(settingKeys.isAppStreamEnabled));
addParam('EnableFlowLogs', this.settings.get(settingKeys.enableFlowLogs));
addParam('DomainName', this.settings.optional(settingKeys.domainName, ''));

const input = {
Expand Down
5 changes: 5 additions & 0 deletions main/config/settings/.defaults.yml
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,11 @@ createServiceCatalogPortfolio: true
# Metadata provided with AWS SDK calls
customUserAgent: 'AwsLabs/SO0144/${self:custom.settings.versionNumber}'

# Flow Logs are a feature that allows users to capture information about network traffic to, from, and within a Subnet.
# Flow Logs are stored using AWS CloudWatch, which can be configured to alarm in the event there is anomalous traffic, or to aid in forensic efforts after a network compromise.
# Recommended: Turning this on captures network traffic information on the hosting account's VPCs and subnets
enableFlowLogs: true

# ================================ Data Egress Feature Settings ===========================================
# NOTE: Following properties are ONLY allowed to change for the initial deployment. It's NOT recommended to change the following properties if you have enabled data egress feature.
# Enable the Egress Store feature would allow researchers to securely egress data from lockdown Workspace
Expand Down
3 changes: 3 additions & 0 deletions main/solution/backend/config/infra/functions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ awsAccountOnboardingHandler:
APP_SM_WORKFLOW: ${self:custom.settings.workflowStateMachineArn}
APP_CUSTOM_USER_AGENT: ${self:custom.settings.customUserAgent}
APP_IS_APP_STREAM_ENABLED: ${self:custom.settings.isAppStreamEnabled}
APP_ENABLE_FLOW_LOGS: ${self:custom.settings.enableFlowLogs}
APP_DOMAIN_NAME: ${self:custom.settings.domainName}

apiHandler:
Expand Down Expand Up @@ -177,6 +178,7 @@ apiHandler:
APP_ROOT_USER_NAME: ${self:custom.settings.rootUserName}
APP_ENABLE_EGRESS_STORE: ${self:custom.settings.enableEgressStore}
APP_IS_APP_STREAM_ENABLED: ${self:custom.settings.isAppStreamEnabled}
APP_ENABLE_FLOW_LOGS: ${self:custom.settings.enableFlowLogs}
APP_EGRESS_STORE_BUCKET_NAME: ${self:custom.settings.egressStoreBucketName}
APP_EGRESS_NOTIFICATION_BUCKET_NAME: ${self:custom.settings.egressNotificationBucketName}
APP_EGRESS_NOTIFICATION_SNS_TOPIC_ARN: ${self:custom.settings.egressNotificationSnsTopicArn}
Expand Down Expand Up @@ -215,5 +217,6 @@ workflowLoopRunner:
APP_EGRESS_STORE_KMS_KEY_ARN: !Sub arn:aws:kms:${AWS::Region}:${AWS::AccountId}:alias/${self:custom.settings.egressStoreKmsKeyAlias}
APP_EGRESS_STORE_KMS_POLICY_WORKSPACE_SID: ${self:custom.settings.egressStoreKmsPolicyWorkspaceSid}
APP_IS_APP_STREAM_ENABLED: ${self:custom.settings.isAppStreamEnabled}
APP_ENABLE_FLOW_LOGS: ${self:custom.settings.enableFlowLogs}
APP_PERMISSION_BOUNDARY_POLICY_STUDY_BUCKET_ARN: !Sub arn:aws:iam::${AWS::AccountId}:policy/${self:custom.settings.permissionBoundaryPolicyStudyBucket}
APP_LOGGING_BUCKET_NAME: ${self:custom.settings.loggingBucketName}
1 change: 1 addition & 0 deletions main/solution/post-deployment/config/infra/functions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ postDeployment:
APP_CUSTOM_USER_AGENT: ${self:custom.settings.customUserAgent}
APP_ENABLE_EGRESS_STORE: ${self:custom.settings.enableEgressStore}
APP_IS_APP_STREAM_ENABLED: ${self:custom.settings.isAppStreamEnabled}
APP_ENABLE_FLOW_LOGS: ${self:custom.settings.enableFlowLogs}
APP_ENVIRONMENTS_BOOTSTRAP_BUCKET_NAME: ${self:custom.settings.environmentsBootstrapBucketName}
APP_STUDY_DATA_BUCKET_NAME: ${self:custom.settings.studyDataBucketName}
APP_ENABLE_NATIVE_USER_POOL_USERS: ${self:custom.settings.enableNativeUserPoolUsers}
Expand Down
1 change: 1 addition & 0 deletions main/solution/ui/config/environment/env-template.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ REACT_APP_VERSION_AND_DATE: ${self:custom.settings.versionAndDate}
REACT_APP_ENABLE_EGRESS_STORE: ${self:custom.settings.enableEgressStore}
REACT_APP_SITE_ENV_TYPE: ${self:custom.settings.envType}
REACT_APP_IS_APP_STREAM_ENABLED: ${self:custom.settings.isAppStreamEnabled}
REACT_APP_ENABLE_FLOW_LOGS: ${self:custom.settings.enableFlowLogs}

# ========================================================================
# Overrides for .env.local
Expand Down

0 comments on commit a36702b

Please sign in to comment.