-
Notifications
You must be signed in to change notification settings - Fork 87
AWS Fargate Deployment
- Create ECR Repository
- Download CxFlow
- Configure CxFlow
- Build Docker Image
- Create SSM Parameters/Secrets
- Define ECS IAM Roles/Permissions
- Define ECS Task Definition
- Create Service
- CxFlow Security Groups
- Monitoring
https://docs.aws.amazon.com/AmazonECR/latest/userguide/repository-create.html
The steps below assume a repository named cxflow
Grab the latest binary from the following:
https://github.com/checkmarx-ts/cx-flow/releases/latest
Download the jar file, for example: cx-flow-1.5.3.jar
<br/. Note There is a JDK 11 version as well - cx-flow-11-1.5.3.jar
Configure CxFlow as per the custom deployment needs, see (Configuration)[https://github.com/checkmarx-ltd/cx-flow/wiki/Configuration]
The configuration should be completed using a file named application.yml. Keep the JAR for CxFlow and the configuration (application.yml) file in the same directory
A base configuration can be found below for 8.9 and 9.0, save each file as application.yml
Note Default bug tracker is Azure in this example, but can be changed
Note Configuration file should be configured for specific use cases, scanning/branching criteria, result feedback, and/or result filtering policy.
8.9 Example application.yml:
server:
port: ${PORT:8080}
logging:
file:
name: cx-flow.log
cx-flow:
# Agreed upon shared API XXXXXXXXXXXXX
tokentoken: xxxx
bug-tracker: Azure
bug-tracker-impl:
- GitHub
- Azure
branches:
- develop
- main
- security
filter-severity:
- High
mitre-url: https://cwe.mitre.org/data/definitions/%s.html
wiki-url: https://checkmarx.atlassian.net/wiki/spaces/AS/pages/79462432/Remediation+Guidance
auto-profile: true
#branch-script: D:\\tmp\Branch.groovy
#zip-exclude: .*.json$, bin\/.*
#list-false-positives: true
checkmarx:
username: xxx
password: xxx
client-secret: 014DF517-39D1-4453-B7B3-9930C563627C
base-url: http://cx.local
multi-tenant: true
configuration: Default Configuration
scan-preset: Checkmarx Default
team: /CxServer/Checkmarx/CxFlow
url: ${checkmarx.base-url}/cxrestapi
preserve-xml: true
incremental: true
#WSDL Config
portal-url: ${checkmarx.base-url}/cxwebinterface/Portal/CxWebService.asmx
jira:
url: https://xxxxx.atlassian.net
username: xxxxxxxxxxxxx
token: xxxx
project: APPSEC
http-timeout: 50000
issue-type: Application Security Bug
priorities:
High: High
Medium: Medium
Low: Low
Informational: Lowest
open-transition: Reopen Issue
close-transition: Close Issue
open-status:
- Open
- Reopened
- In Progress
- False-Positive
- Assistance-Required
closed-status:
- Closed
- Resolved
fields:
- type: result
name: system-date
skip-update: true
offset: 60
jira-field-name: Due Date #Due date (cloud)
jira-field-type: text
- type: result
name: application
jira-field-name: Application
jira-field-type: label
- type: result
name: category
jira-field-name: Category
jira-field-type: label
- type: result
name: cwe
jira-field-name: CWEs
jira-field-type: label
- type: result
name: severity
jira-field-name: Severity
jira-field-type: single-select
- type: result
name: loc
jira-field-name: Line Numbers
jira-field-type: label
- type: static
name: identified-by
jira-field-name: Identified By
jira-field-type: single-select
jira-default-value: Automation
- type: static
name: dependencies
jira-field-name: Dependencies
jira-field-type: multi-select
jira-default-value: Java, AngularJS
- type: result
name: not-exploitable
jira-field-name: False Positive LOC
jira-field-type: label
- type: sca-results
name: package-name
jira-field-name: Package Name
jira-field-type: label
- type: sca-results
name: current-version
jira-field-name: Current Version
jira-field-type: label
- type: sca-results
name: fixed-version
jira-field-name: Fixed Version
jira-field-type: label
- type: sca-results
name: newest-version
jira-field-name: Newest Version
jira-field-type: label
- type: sca-results
name: locations
jira-field-name: Locations
jira-field-type: label
- type: sca-results
name: risk-score
jira-field-name: Risk Score
jira-field-type: label
- type: sca-results
name: dev-dependency
jira-field-name: Development
jira-field-type: single-select
- type: sca-results
name: direct-dependency
jira-field-name: Direct
jira-field-type: single-select
- type: sca-results
name: outdated
jira-field-name: Outdated
jira-field-type: single-select
- type: sca-results
name: violates-policy
jira-field-name: Violates Policy
jira-field-type: single-select
github:
webhook-token: 1234
token: xxx
url: https://github.com
api-url: https://api.github.com/repos/
false-positive-label: false-positive
block-merge: true
error-merge: true
cx-summary: true
gitlab:
webhook-token: 1234
token: xxx
url: https://gitlab.com
api-url: https://gitlab.com/api/v4/
false-positive-label: false-positive
cx-summary: true
bitbucket:
webhook-token: 1234
token: xxx
url: https://api.bitbucket.org
api-path: /2.0
false-positive-label: false-positive
cx-summary: true
azure:
webhook-token: cxflow:1234
token: xxxx
url: https://dev.azure.com/XXXXXX
issue-type: issue
api-version: 5.0
false-positive-label: false-positive
cx-summary: true
block-merge: true
error-merge: true
closed-status: Closed
open-status: Active
json:
file-name-format: "[NAMESPACE]-[REPO]-[BRANCH]-[TIME].json"
data-folder: "/tmp"
cx-xml:
file-name-format: "[NAMESPACE]-[REPO]-[BRANCH]-[TIME].xml"
data-folder: "/tmp"
csv:
file-name-format: "[TEAM]-[PROJECT]-[TIME].csv"
data-folder: "/tmp"
include-header: true
fields:
- header: Customer field (Application)
name: application
default-value: unknown
- header: Primary URL
name: static
- header: severity
name: severity
- header: Vulnerability ID
name: summary
prefix: "[APP]:"
- header: file
name: filename
- header: Vulnerability ID
name: summary
- header: Vulnerability Name
name: category
- header: Category ID
name: cwe
- header: Description
name: summary
prefix: "*"
postfix: "*"
- header: Severity
name: severity
- header: recommendation
name: recommendation
- header: Similarity ID
name: similarity-id
9.0 Example application.yml
server:
port: ${PORT:8080}
logging:
file:
name: cx-flow.log
cx-flow:
# Agreed upon shared API token
token: xxxx
bug-tracker: Azure
bug-tracker-impl:
- GitHub
- Azure
branches:
- develop
- main
- security
filter-severity:
- High
mitre-url: https://cwe.mitre.org/data/definitions/%s.html
wiki-url: https://checkmarx.atlassian.net/wiki/spaces/AS/pages/79462432/Remediation+Guidance
auto-profile: true
#branch-script: D:\\tmp\Branch.groovy
#zip-exclude: .*.json$, bin\/.*
#list-false-positives: true
checkmarx:
version: 9.0
username: xxxxx
password: xxxxx
client-id: resource_owner_client
client-secret: 014DF517-39D1-4453-B7B3-9930C563627C
scope: access_control_api sast_rest_api
base-url: http://cx.local
multi-tenant: true
configuration: Default Configuration
scan-preset: Checkmarx Default
team: /CxServer/Checkmarx/CxFlow
url: ${checkmarx.base-url}/cxrestapi
preserve-xml: true
incremental: true
#WSDL Config
portal-url: ${checkmarx.base-url}/cxwebinterface/Portal/CxWebService.asmx
jira:
url: https://xxxxx.atlassian.net
username: xxxxxxxxxxxxx
token: xxxx
project: APPSEC
http-timeout: 50000
issue-type: Application Security Bug
label-prefix: < CUSTOM PREFIX NAME >
priorities:
High: High
Medium: Medium
Low: Low
Informational: Lowest
open-transition: Reopen Issue
close-transition: Close Issue
open-status:
- Open
- Reopened
- In Progress
- False-Positive
- Assistance-Required
closed-status:
- Closed
- Resolved
fields:
- type: result
name: system-date
skip-update: true
offset: 60
jira-field-name: Due Date #Due date (cloud)
jira-field-type: text
- type: result
name: application
jira-field-name: Application
jira-field-type: label
- type: result
name: category
jira-field-name: Category
jira-field-type: label
- type: result
name: cwe
jira-field-name: CWEs
jira-field-type: label
- type: result
name: severity
jira-field-name: Severity
jira-field-type: single-select
- type: result
name: loc
jira-field-name: Line Numbers
jira-field-type: label
- type: static
name: identified-by
jira-field-name: Identified By
jira-field-type: single-select
jira-default-value: Automation
- type: static
name: dependencies
jira-field-name: Dependencies
jira-field-type: multi-select
jira-default-value: Java, AngularJS
- type: result
name: not-exploitable
jira-field-name: False Positive LOC
jira-field-type: label
- type: sca-results
name: package-name
jira-field-name: Package Name
jira-field-type: label
- type: sca-results
name: current-version
jira-field-name: Current Version
jira-field-type: label
- type: sca-results
name: fixed-version
jira-field-name: Fixed Version
jira-field-type: label
- type: sca-results
name: newest-version
jira-field-name: Newest Version
jira-field-type: label
- type: sca-results
name: locations
jira-field-name: Locations
jira-field-type: label
- type: sca-results
name: risk-score
jira-field-name: Risk Score
jira-field-type: label
- type: sca-results
name: dev-dependency
jira-field-name: Development
jira-field-type: single-select
- type: sca-results
name: direct-dependency
jira-field-name: Direct
jira-field-type: single-select
- type: sca-results
name: outdated
jira-field-name: Outdated
jira-field-type: single-select
- type: sca-results
name: violates-policy
jira-field-name: Violates Policy
jira-field-type: single-select
github:
webhook-token: XXXXXXXXXXXXX
token: xxx
url: https://github.com
api-url: https://api.github.com/repos/
false-positive-label: false-positive
block-merge: true
error-merge: true
cx-summary: true
gitlab:
webhook-token: XXXXXXXXXXXXX
token: xxx
url: https://gitlab.com
api-url: https://gitlab.com/api/v4/
false-positive-label: false-positive
cx-summary: true
bitbucket:
webhook-token: XXXXXXXXXXXXX
token: xxx
url: https://api.bitbucket.org
api-path: /2.0
false-positive-label: false-positive
cx-summary: true
azure:
webhook-token: cxflow:XXXXXXXXXXXXX
token: xxxx
url: https://dev.azure.com/XXXXXX
issue-type: issue
api-version: 5.0
false-positive-label: false-positive
cx-summary: true
block-merge: true
error-merge: true
closed-status: Closed
open-status: Active
json:
file-name-format: "[NAMESPACE]-[REPO]-[BRANCH]-[TIME].json"
data-folder: "/tmp"
cx-xml:
file-name-format: "[NAMESPACE]-[REPO]-[BRANCH]-[TIME].xml"
data-folder: "/tmp"
csv:
file-name-format: "[TEAM]-[PROJECT]-[TIME].csv"
data-folder: "/tmp"
include-header: true
fields:
- header: Customer field (Application)
name: application
default-value: unknown
- header: Primary URL
name: static
- header: severity
name: severity
- header: Vulnerability ID
name: summary
prefix: "[APP]:"
- header: file
name: filename
- header: Vulnerability ID
name: summary
- header: Vulnerability Name
name: category
- header: Category ID
name: cwe
- header: Description
name: summary
prefix: "*"
postfix: "*"
- header: Severity
name: severity
- header: recommendation
name: recommendation
- header: Similarity ID
name: similarity-id
Use the following as a base Docker file
FROM alpine:3.11
VOLUME /tmp
RUN apk add openjdk8-jre && apk update && apk upgrade
ADD cx-flow-1.5.3.jar //
ADD application.yml //
ENTRYPOINT ["java"]
CMD ["-Xms512m", "-Xmx2048m","-Djava.security.egd=file:/dev/./urandom", "-jar", "/cx-flow-1.5.3.jar", "--spring.config.location=/application.yml", "--web"]
EXPOSE 8080:8080
Build the image, and tag it for ECR and push to the remote repository (created in previous step)
$(aws ecr get-login --no-include-email --region us-east-1)
docker build -t cxflow .
docker tag cxflow XXXXXXXXXX.dkr.ecr.us-east-1.amazonaws.com/cxflow
docker push XXXXXXXXXX.dkr.ecr.us-east-1.amazonaws.com/cxflow
Note XXXXXXXXXX is the AWS account, and this example is using the us-east-1 region. This image is by default tagged/pushed as latest unless specified
There are several SSM parameters (mainly secure SSM parameters). Feel free to give different naming patterns, but remember to reflect the changes in the ECS task definition as well as the IAM policy references. These are the commands for using the AWS CLI and are leveraging the base KMS key. Please refer to SSM documentation for variations. Console configuration is also possible.
#Checkmarx User
aws ssm put-parameter --name "/cxflow/checkmarx/username" --value "admin" --type SecureString
#Checkmarx Password
aws ssm put-parameter --name "/cxflow/checkmarx/password" --value "XXXXXX" --type SecureString
#It is worth noting that this below reference will result in what the url resolves. Go into the console and update if required (validate this)
aws ssm put-parameter --name "/cxflow/checkmarx/url" --value "https://cx.local" --type String
#This token is associated with the default endpoint for driving a scan/results but that is not also associated with a
#webhook event payload (which is a separate token as per below)
aws ssm put-parameter --name "/cxflow/token" --value "XXXXXX" --type SecureString
#Preshared secret between GitHub and CxFlow - used when registering the webhook for auth
aws ssm put-parameter --name "/cxflow/github/webhook-token" --value "XXXXXX" --type SecureString
#GitHub Service account API token (Personal access token) used for driving git scanning in Checkmarx
#posting MD comments in PRs, Updating statuses, Creating GitHub issues (if applicable)
aws ssm put-parameter --name "/cxflow/github/token" --value "XXXXXX" --type SecureString
#Preshared secret between GitLab and CxFlow - used when registering the webhook for auth
aws ssm put-parameter --name "/cxflow/gitlab/webhook-token" --value "XXXXXX" --type SecureString
#GitLab Service account API token used for driving git scanning in Checkmarx
#posting MD comments in MRs, Creating GitLab issues (if applicable)
aws ssm put-parameter --name "/cxflow/gitlab/token" --value "XXXXXX" --type SecureString
#Same pattern as above for GitHub/GitLab, instead for Azure DevOps and BitBucket
aws ssm put-parameter --name "/cxflow/azure/webhook-token" --value "<user>:XXXXXX" --type SecureString
aws ssm put-parameter --name "/cxflow/azure/token" --value "XXXXXX" --type SecureString
aws ssm put-parameter --name "/cxflow/bitbucket/webhook-token" --value "XXXXXX" --type SecureString
aws ssm put-parameter --name "/cxflow/bitbucket/token" --value "<use>:XXXXXX" --type SecureString
Note Using SSM will avoid the use of any unencrypted credentials and will be automatically injected into the CxFlow process.
ECS will need appropriate access to IAM resources including SSM Parameters, KMS key, Cloud Watch log streams, ECR registry as well as must be able to be assumed.
The trust policy must be defined as the following to allow this:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": "ecs-tasks.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
Note The Role must be associated with ECS and Container Service Definition. The role should contain the base managed policy of AmazonECSTaskExecutionRolePolicy to ensure proper access is given to base ECS resources from within task execution. Additional IAM policy is used to drive the above mentioned SSM parameters / KMS keys, Cloudwatch logs, etc. This can be used as a starting point but should be adjusted or restricted further based on specific needs (i.e. log event groups/streams can be narrowed appropriately):
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ssm:GetParameter",
"ssm:GetParametersByPath",
"ssm:GetParameters",
"kms:Decrypt"
],
"Resource": [
"arn:aws:ssm:us-east-1:<Acct ID>:parameter/cxflow/*",
"arn:aws:kms:us-east-1:<Acct ID>:key/<KMS Key ID>"
]
},
{
"Effect": "Allow",
"Action": [
"ecr:GetAuthorizationToken",
"ecr:BatchCheckLayerAvailability",
"ecr:GetDownloadUrlForLayer",
"ecr:BatchGetImage",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "*"
}
]
}
The following ECS Task Definition can be used to define the CxFlow Task and inject the appropriate ENV variables linked from SSM Secure Parameters (note the secrets section - there are direct links to the ssm parameter paths as defined within the same region and the ENV variables that will be inject/expected in CxFlow) - also note the log definition that will send output to cloudwatch logs:
fargate.json
{
"containerDefinitions": [{
"portMappings": [{
"hostPort": 8080,
"containerPort": 8080,
"protocol": "http"
}],
"essential": true,
"name": "cxflow-container",
"image": "275043232443.dkr.ecr.us-east-1.amazonaws.com/cxflow:latest",
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/app/cxflow",
"awslogs-region": "us-east-1",
"awslogs-stream-prefix": "cx-"
}
},
"secrets": [{
"name": "CHECKMARX_USERNAME",
"valueFrom": "/cxflow/checkmarx/username"
},
{
"name": "CHECKMARX_PASSWORD",
"valueFrom": "/cxflow/checkmarx/password"
},
{
"name": "CHECKMARX_BASE_URL",
"valueFrom": "/cxflow/checkmarx/url"
},
{
"name": "CX_FLOW_TOKEN",
"valueFrom": "/cxflow/token"
},
{
"name": "GITHUB_TOKEN",
"valueFrom": "/cxflow/github/token"
},
{
"name": "GITHUB_WEBHOOK_TOKEN",
"valueFrom": "/cxflow/github/webhook-token"
},
{
"name": "AZURE_TOKEN",
"valueFrom": "/cxflow/azure/token"
},
{
"name": "AZURE_WEBHOOK_TOKEN",
"valueFrom": "/cxflow/azure/webhook-token"
},
{
"name": "GITLAB_TOKEN",
"valueFrom": "/cxflow/gitlab/token"
},
{
"name": "GITLAB_WEBHOOK_TOKEN",
"valueFrom": "/cxflow/gitlab/webhook-token"
},
{
"name": "BITBUCKET_TOKEN",
"valueFrom": "/cxflow/bitbucket/token"
},
{
"name": "BITBUCKET_WEBHOOK_TOKEN",
"valueFrom": "/cxflow/bitbucket/webhook-token"
}]
}
],
"networkMode": "awsvpc",
"executionRoleArn": "arn:aws:iam::275043232443:role/ecsTaskExecutionRole",
"taskRoleArn": "arn:aws:iam::275043232443:role/ecsTaskExecutionRole",
"memory": "2048",
"cpu": "512",
"requiresCompatibilities": [
"FARGATE"
],
"family": "cxflow"
}
The following command can be used to define the task definition within ECS (using AWS CLI):
aws ecs register-task-definition --cli-input-json file://fargate.json
To create a service to run the defined task the following can be leveraged:
aws ecs create-service --cluster FieldDevelopment --service-name cxflow-service --task-definition cxflow:1 --desired-count 1 --launch-type "FARGATE" --network-configuration "awsvpcConfiguration={subnets=[subnet-XXXXXX],securityGroups=[sg-XXXXXX,sg-XXXXXXX], assignPublicIp=ENABLED}"
Note The --task-definition # (i.e. cxflow:1) is linked directly with the current version, which is applicable to the number of times the definition has been revised.
Note This command should be tailored to the specific use case. Specifically, network architecture must be considered (awsvpcConfiguration). The above assigns a Public IP directly, which will not be appropriate for most (if not all) deployments. This should consider any ALB, NGINX and other containers within the orhestration.
CxFlow should NOT be exposed directly on the internet without considering the requirements for connectivity.
GitHub, Azure DevOps, Bitbucket all have IP CIDR ranges that can be referenced for white-listing:
GitHub: https://help.github.com/en/github/authenticating-to-github/about-githubs-ip-addresses
Azure: https://docs.microsoft.com/en-us/azure/devops/organizations/security/allow-list-ip-url?view=azure-devops
BitBucket: https://confluence.atlassian.com/bitbucket/what-are-the-bitbucket-cloud-ip-addresses-i-should-use-to-configure-my-corporate-firewall-343343385.html
On-premise architecture and security controls should be reviewed and implemented on a per-customer basis.
Note GitLab does not have a defined CIDR range and must be considered with caution
Note CxFlow should be placed into a network zone / DMZ that does not have any network access beyond required connectivity points.
Actuator endpoint can be used to monitor whether the service is up / online:
Example: http://cxflow.XXXXX:8080/actuator/health
{
"status": "UP"
}
Note Actuator can be leveraged for many other monitoring purposes:
https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-features.html