diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c8c233e95a..7d7da9f2eb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -104,6 +104,35 @@ jobs: run: cd .repo && npx projen package:js - name: Collect js Artifact run: mv .repo/dist dist + package-java: + needs: build + runs-on: ubuntu-latest + permissions: {} + if: "! needs.build.outputs.self_mutation_happened" + steps: + - uses: actions/setup-java@v3 + with: + distribution: temurin + java-version: 11.x + - uses: actions/setup-node@v3 + with: + node-version: 14.x + - name: Download build artifacts + uses: actions/download-artifact@v3 + with: + name: build-artifact + path: dist + - name: Restore build artifact permissions + run: cd dist && setfacl --restore=permissions-backup.acl + continue-on-error: true + - name: Prepare Repository + run: mv dist .repo + - name: Install Dependencies + run: cd .repo && yarn install --check-files --frozen-lockfile + - name: Create java artifact + run: cd .repo && npx projen package:java + - name: Collect java Artifact + run: mv .repo/dist dist package-python: needs: build runs-on: ubuntu-latest @@ -132,3 +161,31 @@ jobs: run: cd .repo && npx projen package:python - name: Collect python Artifact run: mv .repo/dist dist + package-go: + needs: build + runs-on: ubuntu-latest + permissions: {} + if: "! needs.build.outputs.self_mutation_happened" + steps: + - uses: actions/setup-node@v3 + with: + node-version: 14.x + - uses: actions/setup-go@v3 + with: + go-version: ^1.16.0 + - name: Download build artifacts + uses: actions/download-artifact@v3 + with: + name: build-artifact + path: dist + - name: Restore build artifact permissions + run: cd dist && setfacl --restore=permissions-backup.acl + continue-on-error: true + - name: Prepare Repository + run: mv dist .repo + - name: Install Dependencies + run: cd .repo && yarn install --check-files --frozen-lockfile + - name: Create go artifact + run: cd .repo && npx projen package:go + - name: Collect go Artifact + run: mv .repo/dist dist diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 440cfdfd68..08367954aa 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -105,6 +105,46 @@ jobs: NPM_REGISTRY: registry.npmjs.org NPM_TOKEN: ${{ secrets.NPM_TOKEN }} run: npx -p publib@latest publib-npm + release_maven: + name: Publish to Maven Central + needs: release + runs-on: ubuntu-latest + permissions: + contents: read + if: needs.release.outputs.latest_commit == github.sha + steps: + - uses: actions/setup-java@v3 + with: + distribution: temurin + java-version: 11.x + - uses: actions/setup-node@v3 + with: + node-version: 14.x + - name: Download build artifacts + uses: actions/download-artifact@v3 + with: + name: build-artifact + path: dist + - name: Restore build artifact permissions + run: cd dist && setfacl --restore=permissions-backup.acl + continue-on-error: true + - name: Prepare Repository + run: mv dist .repo + - name: Install Dependencies + run: cd .repo && yarn install --check-files --frozen-lockfile + - name: Create java artifact + run: cd .repo && npx projen package:java + - name: Collect java Artifact + run: mv .repo/dist dist + - name: Release + env: + MAVEN_ENDPOINT: https://s01.oss.sonatype.org + MAVEN_GPG_PRIVATE_KEY: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }} + MAVEN_GPG_PRIVATE_KEY_PASSPHRASE: ${{ secrets.MAVEN_GPG_PRIVATE_KEY_PASSPHRASE }} + MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }} + MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }} + MAVEN_STAGING_PROFILE_ID: ${{ secrets.MAVEN_STAGING_PROFILE_ID }} + run: npx -p publib@latest publib-maven release_pypi: name: Publish to PyPI needs: release @@ -140,3 +180,39 @@ jobs: TWINE_USERNAME: ${{ secrets.TWINE_USERNAME }} TWINE_PASSWORD: ${{ secrets.TWINE_PASSWORD }} run: npx -p publib@latest publib-pypi + release_golang: + name: Publish to GitHub Go Module Repository + needs: release + runs-on: ubuntu-latest + permissions: + contents: read + if: needs.release.outputs.latest_commit == github.sha + steps: + - uses: actions/setup-node@v3 + with: + node-version: 14.x + - uses: actions/setup-go@v3 + with: + go-version: ^1.16.0 + - name: Download build artifacts + uses: actions/download-artifact@v3 + with: + name: build-artifact + path: dist + - name: Restore build artifact permissions + run: cd dist && setfacl --restore=permissions-backup.acl + continue-on-error: true + - name: Prepare Repository + run: mv dist .repo + - name: Install Dependencies + run: cd .repo && yarn install --check-files --frozen-lockfile + - name: Create go artifact + run: cd .repo && npx projen package:go + - name: Collect go Artifact + run: mv .repo/dist dist + - name: Release + env: + GIT_USER_NAME: cdklabs-automation + GIT_USER_EMAIL: cdklabs-automation@amazon.com + GITHUB_TOKEN: ${{ secrets.GO_GITHUB_TOKEN }} + run: npx -p publib@latest publib-golang diff --git a/.mergify.yml b/.mergify.yml index 891c7aa0f0..eee2bd05e9 100644 --- a/.mergify.yml +++ b/.mergify.yml @@ -7,7 +7,9 @@ queue_rules: - -label~=(do-not-merge) - status-success=build - status-success=package-js + - status-success=package-java - status-success=package-python + - status-success=package-go pull_request_rules: - name: Automatic merge on approval and successful build actions: @@ -24,4 +26,6 @@ pull_request_rules: - -label~=(do-not-merge) - status-success=build - status-success=package-js + - status-success=package-java - status-success=package-python + - status-success=package-go diff --git a/.projen/tasks.json b/.projen/tasks.json index 50a3c5d0f9..ceec301b97 100644 --- a/.projen/tasks.json +++ b/.projen/tasks.json @@ -149,8 +149,32 @@ { "spawn": "package:js" }, + { + "spawn": "package:java" + }, { "spawn": "package:python" + }, + { + "spawn": "package:go" + } + ] + }, + "package:go": { + "name": "package:go", + "description": "Create go language bindings", + "steps": [ + { + "exec": "jsii-pacmak -v --target go" + } + ] + }, + "package:java": { + "name": "package:java", + "description": "Create java language bindings", + "steps": [ + { + "exec": "jsii-pacmak -v --target java" } ] }, diff --git a/.projenrc.js b/.projenrc.js index a02aa4aef8..d84171b151 100644 --- a/.projenrc.js +++ b/.projenrc.js @@ -19,21 +19,21 @@ const project = new awscdk.AwsCdkConstructLibrary({ distName: 'cdk-nag', module: 'cdk_nag', }, - // publishToNuget: { - // packageId: 'Cdklabs.CdkNag', - // dotNetNamespace: 'Cdklabs.CdkNag', - // }, - // publishToMaven: { - // mavenGroupId: 'io.github.cdklabs', - // javaPackage: 'io.github.cdklabs.cdknag', - // mavenArtifactId: 'cdknag', - // mavenEndpoint: 'https://s01.oss.sonatype.org', - // }, - // publishToGo: { - // moduleName: 'github.com/cdklabs/cdk-nag-go', - // gitUserName: 'cdklabs-automation', - // gitUserEmail: 'cdklabs-automation@amazon.com', - // }, + publishToNuget: { + packageId: 'Cdklabs.CdkNag', + dotNetNamespace: 'Cdklabs.CdkNag', + }, + publishToMaven: { + mavenGroupId: 'io.github.cdklabs', + javaPackage: 'io.github.cdklabs.cdknag', + mavenArtifactId: 'cdknag', + mavenEndpoint: 'https://s01.oss.sonatype.org', + }, + publishToGo: { + moduleName: 'github.com/cdklabs/cdk-nag-go', + gitUserName: 'cdklabs-automation', + gitUserEmail: 'cdklabs-automation@amazon.com', + }, projenUpgradeSecret: 'PROJEN_GITHUB_TOKEN', autoApproveOptions: { allowedUsernames: ['cdklabs-automation', 'dontirun'], diff --git a/package.json b/package.json index 2f98d467fc..291276c3c8 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,8 @@ "eslint": "npx projen eslint", "package": "npx projen package", "package-all": "npx projen package-all", + "package:go": "npx projen package:go", + "package:java": "npx projen package:java", "package:js": "npx projen package:js", "package:python": "npx projen package:python", "post-compile": "npx projen post-compile", @@ -118,9 +120,19 @@ "jsii": { "outdir": "dist", "targets": { + "java": { + "package": "io.github.cdklabs.cdknag", + "maven": { + "groupId": "io.github.cdklabs", + "artifactId": "cdknag" + } + }, "python": { "distName": "cdk-nag", "module": "cdk_nag" + }, + "go": { + "moduleName": "github.com/cdklabs/cdk-nag-go" } }, "tsc": { diff --git a/src/rules/ec2/EC2SecurityGroupOnlyTcp443.ts b/src/rules/ec2/EC2SecurityGroupOnlyTcp443.ts index 67afc9a884..4977c3f1fa 100644 --- a/src/rules/ec2/EC2SecurityGroupOnlyTcp443.ts +++ b/src/rules/ec2/EC2SecurityGroupOnlyTcp443.ts @@ -13,84 +13,88 @@ import { NagRuleCompliance, NagRules } from '../../nag-rules'; */ export default Object.defineProperty( (node: CfnResource): NagRuleCompliance => { - if (node instanceof CfnSecurityGroup) { const ingressRules = Stack.of(node).resolve(node.securityGroupIngress); - + if (ingressRules != undefined) { //For each ingress rule, check that only TCP 443 is allowed from 0/0 - for (const rule of ingressRules) { - - const resolvedcidrIp = NagRules.resolveIfPrimitive(node, Stack.of(node).resolve(rule).cidrIp); - const resolvedcidrIpv6 = NagRules.resolveIfPrimitive(node, Stack.of(node).resolve(rule).cidrIpv6); - + for (const rule of ingressRules) { + const resolvedcidrIp = NagRules.resolveIfPrimitive( + node, + Stack.of(node).resolve(rule).cidrIp + ); + const resolvedcidrIpv6 = NagRules.resolveIfPrimitive( + node, + Stack.of(node).resolve(rule).cidrIpv6 + ); + // if ipv4 if (resolvedcidrIp) { // if the rule is not open to the world, it is compliant - if (!(resolvedcidrIp.includes('/0'))) { - return NagRuleCompliance.COMPLIANT + if (!resolvedcidrIp.includes('/0')) { + return NagRuleCompliance.COMPLIANT; } } // if ipv6 if (resolvedcidrIpv6) { // if the rule is not open to the world, it is compliant - if (!(resolvedcidrIpv6.includes('/0'))) { - return NagRuleCompliance.COMPLIANT + if (!resolvedcidrIpv6.includes('/0')) { + return NagRuleCompliance.COMPLIANT; } } - + const ipProtocol = NagRules.resolveIfPrimitive( node, Stack.of(node).resolve(rule).ipProtocol ); - const toPort = NagRules.resolveIfPrimitive(node, Stack.of(node).resolve(rule).toPort); - + const toPort = NagRules.resolveIfPrimitive( + node, + Stack.of(node).resolve(rule).toPort + ); + if (!toPort) { - return NagRuleCompliance.NON_COMPLIANT + return NagRuleCompliance.NON_COMPLIANT; } if (!(toPort === 443 && ipProtocol === 'tcp')) { return NagRuleCompliance.NON_COMPLIANT; } } - } - - - return NagRuleCompliance.COMPLIANT; + } + return NagRuleCompliance.COMPLIANT; } else if (node instanceof CfnSecurityGroupIngress) { - const ipProtocol = NagRules.resolveIfPrimitive(node, node.ipProtocol); - const toPort = NagRules.resolveIfPrimitive(node, node.toPort); - const resolvedcidrIp = NagRules.resolveIfPrimitive(node, node.cidrIp); - const resolvedcidrIpv6 = NagRules.resolveIfPrimitive(node, node.cidrIpv6); + const ipProtocol = NagRules.resolveIfPrimitive(node, node.ipProtocol); + const toPort = NagRules.resolveIfPrimitive(node, node.toPort); + const resolvedcidrIp = NagRules.resolveIfPrimitive(node, node.cidrIp); + const resolvedcidrIpv6 = NagRules.resolveIfPrimitive(node, node.cidrIpv6); - // if ipv4 - if (resolvedcidrIp){ - if (resolvedcidrIp === '0.0.0.0/0'){ - if (toPort === 443 && ipProtocol === 'tcp'){ - console.log(resolvedcidrIp, toPort, ipProtocol) - return NagRuleCompliance.COMPLIANT - } - return NagRuleCompliance.NON_COMPLIANT + // if ipv4 + if (resolvedcidrIp) { + if (resolvedcidrIp === '0.0.0.0/0') { + if (toPort === 443 && ipProtocol === 'tcp') { + return NagRuleCompliance.COMPLIANT; } - return NagRuleCompliance.COMPLIANT + return NagRuleCompliance.NON_COMPLIANT; } + return NagRuleCompliance.COMPLIANT; + } - // if ipv6 - if (resolvedcidrIpv6){ - if (resolvedcidrIpv6 === '::/0'){ - if (toPort === 443 && ipProtocol === 'tcp'){ - return NagRuleCompliance.COMPLIANT - } - return NagRuleCompliance.NON_COMPLIANT + // if ipv6 + if (resolvedcidrIpv6) { + if (resolvedcidrIpv6 === '::/0') { + if (toPort === 443 && ipProtocol === 'tcp') { + return NagRuleCompliance.COMPLIANT; } - return NagRuleCompliance.COMPLIANT + return NagRuleCompliance.NON_COMPLIANT; } + return NagRuleCompliance.COMPLIANT; + } } - + return NagRuleCompliance.NOT_APPLICABLE; }, - + 'name', { value: parse(__filename).name } ); diff --git a/test/rules/EC2.test.ts b/test/rules/EC2.test.ts index 108f23486c..0b14563546 100644 --- a/test/rules/EC2.test.ts +++ b/test/rules/EC2.test.ts @@ -552,7 +552,7 @@ describe('Amazon Elastic Block Store (EBS)', () => { describe('EC2SecurityGroupOnlyTcp443: Security Groups should only allow TCP 443 from everything', () => { const ruleId = 'EC2SecurityGroupOnlyTcp443'; - + test('a non compliant ipv6 rule', () => { new CfnSecurityGroup(stack, 'rSecurityGroup', { groupDescription: 'security group tcp port 80 open on port 80', @@ -566,7 +566,7 @@ describe('EC2SecurityGroupOnlyTcp443: Security Groups should only allow TCP 443 }); validateStack(stack, ruleId, TestType.NON_COMPLIANCE); }); - + test('a compliant ipv6 rule', () => { new CfnSecurityGroup(stack, 'rSecurityGroup', { groupDescription: 'ipv6 to non ::0/0', @@ -581,7 +581,6 @@ describe('EC2SecurityGroupOnlyTcp443: Security Groups should only allow TCP 443 validateStack(stack, ruleId, TestType.COMPLIANCE); }); - test('no specified port', () => { new CfnSecurityGroup(stack, 'rSecurityGroup', { groupDescription: 'security group tcp port 80 open', @@ -594,7 +593,7 @@ describe('EC2SecurityGroupOnlyTcp443: Security Groups should only allow TCP 443 }); validateStack(stack, ruleId, TestType.NON_COMPLIANCE); }); - + test('tcp port other than 443 from 0/0', () => { new CfnSecurityGroup(stack, 'rSecurityGroup', { groupDescription: 'security group tcp port 80 open', @@ -623,7 +622,7 @@ describe('EC2SecurityGroupOnlyTcp443: Security Groups should only allow TCP 443 validateStack(stack, ruleId, TestType.NON_COMPLIANCE); }); - test('ipv4 tcp443 from anywhere', () => { + test('ipv4 tcp443 from anywhere', () => { new CfnSecurityGroup(stack, 'rSecurityGroup2', { groupDescription: 'security group with tcp 443 ingress allowed', securityGroupIngress: [ @@ -633,11 +632,11 @@ describe('EC2SecurityGroupOnlyTcp443: Security Groups should only allow TCP 443 cidrIp: '0.0.0.0/0', }, ], - }); - validateStack(stack, ruleId, TestType.COMPLIANCE) + }); + validateStack(stack, ruleId, TestType.COMPLIANCE); }); - test('tcp80 from 10/8', () => { + test('tcp80 from 10/8', () => { new CfnSecurityGroup(stack, 'rSecurityGroup2', { groupDescription: 'security group with tcp 443 ingress allowed', securityGroupIngress: [ @@ -648,64 +647,62 @@ describe('EC2SecurityGroupOnlyTcp443: Security Groups should only allow TCP 443 }, ], }); - validateStack(stack, ruleId, TestType.COMPLIANCE) + validateStack(stack, ruleId, TestType.COMPLIANCE); }); test('ingressGroupCompliant', () => { new CfnSecurityGroupIngress(stack, 'ingressGroup', { ipProtocol: 'tcp', toPort: 443, - cidrIp: '0.0.0.0/0' + cidrIp: '0.0.0.0/0', }); - validateStack(stack, ruleId, TestType.COMPLIANCE) - }) + validateStack(stack, ruleId, TestType.COMPLIANCE); + }); test('ingressGroupNonCompliant', () => { new CfnSecurityGroupIngress(stack, 'ingressGroup', { ipProtocol: 'tcp', toPort: 80, - cidrIp: '0.0.0.0/0' + cidrIp: '0.0.0.0/0', }); - validateStack(stack, ruleId, TestType.NON_COMPLIANCE) - }) + validateStack(stack, ruleId, TestType.NON_COMPLIANCE); + }); test('ingressGroupNonCompliant', () => { new CfnSecurityGroupIngress(stack, 'ingressGroup', { ipProtocol: 'tcp', toPort: 443, - cidrIp: '10.0.0.0/8' + cidrIp: '10.0.0.0/8', }); - validateStack(stack, ruleId, TestType.COMPLIANCE) - }) + validateStack(stack, ruleId, TestType.COMPLIANCE); + }); test('ingressgroup, ipv6 compliant', () => { new CfnSecurityGroupIngress(stack, 'ingressGroup', { ipProtocol: 'tcp', toPort: 443, - cidrIpv6: '::/0' + cidrIpv6: '::/0', }); - validateStack(stack, ruleId, TestType.COMPLIANCE) - }) + validateStack(stack, ruleId, TestType.COMPLIANCE); + }); test('ingressGroup, non compliant', () => { new CfnSecurityGroupIngress(stack, 'ingressGroup', { ipProtocol: 'tcp', toPort: 80, - cidrIpv6: '::/0' + cidrIpv6: '::/0', }); - validateStack(stack, ruleId, TestType.NON_COMPLIANCE) - }) + validateStack(stack, ruleId, TestType.NON_COMPLIANCE); + }); test('ingressGroupnonopenCompliant', () => { new CfnSecurityGroupIngress(stack, 'ingressGroup', { ipProtocol: 'tcp', toPort: 80, - cidrIpv6: 'FE80:CD00:0:CDE:1257:0:211E:729C/64' + cidrIpv6: 'FE80:CD00:0:CDE:1257:0:211E:729C/64', }); - validateStack(stack, ruleId, TestType.COMPLIANCE) - }) - - + validateStack(stack, ruleId, TestType.COMPLIANCE); + }); }); describe('EC2IMDSv2: Instances use IMDSv2', () => { diff --git a/yarn.lock b/yarn.lock index 58423388fe..6ab2ff99dc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -906,7 +906,7 @@ resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.6.0.tgz#efcbd41937f9ae7434c714ab698604822d890759" integrity sha512-G/AdOadiZhnJp0jXCaBQU449W2h716OW/EoXeYkCytxKL06X1WCXB4DZpp8TpZ8eyIJVS1cw4lrlkkSYU21cDw== -"@types/responselike@*", "@types/responselike@1.0.0", "@types/responselike@^1.0.0": +"@types/responselike@*", "@types/responselike@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@types/responselike/-/responselike-1.0.0.tgz#251f4fe7d154d2bad125abe1b429b23afd262e29" integrity sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA== @@ -2872,7 +2872,7 @@ globby@^11.0.4, globby@^11.1.0: merge2 "^1.4.1" slash "^3.0.0" -got@12.3.1, got@^12.1.0: +got@^12.1.0: version "12.3.1" resolved "https://registry.yarnpkg.com/got/-/got-12.3.1.tgz#79d6ebc0cb8358c424165698ddb828be56e74684" integrity sha512-tS6+JMhBh4iXMSXF6KkIsRxmloPln31QHDlcb6Ec3bzxjjFJFr/8aXdpyuLmVc9I4i2HyBHYw1QU5K1ruUdpkw==