From 5d3c4a3258195ad2764bac7ef1f04816d857d64c Mon Sep 17 00:00:00 2001 From: Aaron Walker Date: Thu, 1 Apr 2021 13:08:11 +0200 Subject: [PATCH 1/3] brings task def features inline with the ecs-services component --- ecs-task.cfhighlander.rb | 2 + ecs-task.cfndsl.rb | 144 ++++++++++++++++++++++++++++--------- tests/depends_on.test.yaml | 27 +++++++ tests/ec2.test.yaml | 4 +- 4 files changed, 140 insertions(+), 37 deletions(-) create mode 100644 tests/depends_on.test.yaml diff --git a/ecs-task.cfhighlander.rb b/ecs-task.cfhighlander.rb index 4890e3b..c50b912 100644 --- a/ecs-task.cfhighlander.rb +++ b/ecs-task.cfhighlander.rb @@ -2,6 +2,8 @@ Description "ecs-task - #{component_name} - #{component_version}" + DependsOn 'lib-iam' + Parameters do ComponentParam 'EnvironmentName', 'dev', isGlobal: true ComponentParam 'EnvironmentType', 'development', allowedValues: ['development','production'], isGlobal: true diff --git a/ecs-task.cfndsl.rb b/ecs-task.cfndsl.rb index 44a2a49..bbaf367 100644 --- a/ecs-task.cfndsl.rb +++ b/ecs-task.cfndsl.rb @@ -18,7 +18,8 @@ RetentionInDays "#{log_retention}" } - definitions, task_volumes, secrets, secrets_policy = Array.new(4){[]} + definitions, task_volumes, secrets = Array.new(4){[]} + secrets_policy = {} task_definition = external_parameters.fetch(:task_definition, {}) task_definition.each do |task_name, task| @@ -46,6 +47,10 @@ } } + if task.has_key?('log_pattern') + task_def[:LogConfiguration][:Options]["awslogs-multiline-pattern"] = task['log_pattern'] + end + task_def.merge!({ MemoryReservation: task['memory'] }) if task.has_key?('memory') task_def.merge!({ Cpu: task['cpu'] }) if task.has_key?('cpu') @@ -99,10 +104,13 @@ task_def.merge!({MountPoints: mount_points }) end - # volumes from + # add volumes from if task.key?('volumes_from') - task['volumes_from'].each do |source_container| - task_def.merge!({ VolumesFrom: [ SourceContainer: source_container ] }) + if task['volumes_from'].kind_of?(Array) + task['volumes_from'].each do |source_container| + volumes_from << { SourceContainer: source_container } + end + task_def.merge!({ VolumesFrom: volumes_from }) end end @@ -119,37 +127,91 @@ task_def.merge!({PortMappings: port_mapppings}) end + # add DependsOn + # The dependencies defined for container startup and shutdown. A container can contain multiple dependencies. When a dependency is defined for container startup, for container shutdown it is reversed. + # For tasks using the EC2 launch type, the container instances require at least version 1.3.0 of the container agent to enable container dependencies + depends_on = [] + if !(task['depends_on'].nil?) + task['depends_on'].each do |name,value| + depends_on << { ContainerName: name, Condition: value} + end + end + + linux_parameters = {} + + if task.key?('cap_add') + linux_parameters[:Capabilities] = {Add: task['cap_add']} + end + + if task.key?('cap_drop') + if linux_parameters.key?(:Capabilities) + linux_parameters[:Capabilities][:Drop] = task['cap_drop'] + else + linux_parameters[:Capabilities] = {Drop: task['cap_drop']} + end + end + + if task.key?('init') + linux_parameters[:InitProcessEnabled] = task['init'] + end + + if task.key?('memory_swap') + linux_parameters[:MaxSwap] = task['memory_swap'].to_i + end + + if task.key?('shm_size') + linux_parameters[:SharedMemorySize] = task['shm_size'].to_i + end + + if task.key?('memory_swappiness') + linux_parameters[:Swappiness] = task['memory_swappiness'].to_i + end + + task_def.merge!({LinuxParameters: linux_parameters}) if linux_parameters.any? task_def.merge!({EntryPoint: task['entrypoint'] }) if task.key?('entrypoint') task_def.merge!({Command: task['command'] }) if task.key?('command') task_def.merge!({HealthCheck: task['healthcheck'] }) if task.key?('healthcheck') task_def.merge!({WorkingDirectory: task['working_dir'] }) if task.key?('working_dir') + task_def.merge!({Privileged: task['privileged'] }) if task.key?('privileged') + task_def.merge!({User: task['user'] }) if task.key?('user') + task_def.merge!({DependsOn: depends_on }) if depends_on.length > 0 + task_def.merge!({ ExtraHosts: task['extra_hosts'] }) if task.has_key?('extra_hosts') if task.key?('secrets') - + if task['secrets'].key?('ssm') secrets.push *task['secrets']['ssm'].map {|k,v| { Name: k, ValueFrom: v.is_a?(String) && v.start_with?('/') ? FnSub("arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter#{v}") : v }} resources = task['secrets']['ssm'].map {|k,v| v.is_a?(String) && v.start_with?('/') ? FnSub("arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter#{v}") : v } - secrets_policy.push iam_policy_allow('ssm-secrets','ssm:GetParameters', resources) + secrets_policy['ssm-secrets'] = { + 'action' => 'ssm:GetParameters', + 'resource' => resources + } task['secrets'].reject! { |k| k == 'ssm' } end - + if task['secrets'].key?('secretsmanager') secrets.push *task['secrets']['secretsmanager'].map {|k,v| { Name: k, ValueFrom: v.is_a?(String) && v.start_with?('/') ? FnSub("arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:#{v}") : v }} resources = task['secrets']['secretsmanager'].map {|k,v| v.is_a?(String) && v.start_with?('/') ? FnSub("arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:#{v}-*") : v } - secrets_policy.push iam_policy_allow('secretsmanager','secretsmanager:GetSecretValue', resources) + secrets_policy['secretsmanager'] = { + 'action' => 'secretsmanager:GetSecretValue', + 'resource' => resources + } task['secrets'].reject! { |k| k == 'secretsmanager' } end - + unless task['secrets'].empty? secrets.push *task['secrets'].map {|k,v| { Name: k, ValueFrom: v.is_a?(String) && v.start_with?('/') ? FnSub("arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter#{v}") : v }} resources = task['secrets'].map {|k,v| v.is_a?(String) && v.start_with?('/') ? FnSub("arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter#{v}") : v } - secrets_policy.push iam_policy_allow('ssm-secrets','ssm:GetParameters', resources) + secrets_policy['ssm-secrets-inline'] = { + 'action' => 'ssm:GetParameters', + 'resource' => resources + } end - + if secrets.any? task_def.merge!({Secrets: secrets}) end - + end definitions << task_def @@ -169,41 +231,53 @@ task_volumes << object end + # add task placement constraints + task_constraints =[]; + task_placement_constraints = external_parameters.fetch(:task_placement_constraints, []) + task_placement_constraints.each do |cntr| + object = {Type: "memberOf"} + object.merge!({ Expression: FnSub(cntr)}) + task_constraints << object + end iam_policies = external_parameters.fetch(:iam_policies, {}) + service_discovery = external_parameters.fetch(:service_discovery, {}) unless iam_policies.empty? - - policies = [] - iam_policies.each do |name,policy| - policies << iam_policy_allow(name,policy['action'],policy['resource'] || '*') + + unless service_discovery.empty? + iam_policies['ecs-service-discovery'] = { + 'action' => %w( + servicediscovery:RegisterInstance + servicediscovery:DeregisterInstance + servicediscovery:DiscoverInstances + servicediscovery:Get* + servicediscovery:List* + route53:GetHostedZone + route53:ListHostedZonesByName + route53:ChangeResourceRecordSets + route53:CreateHealthCheck + route53:GetHealthCheck + route53:DeleteHealthCheck + route53:UpdateHealthCheck + ) + } end - + IAM_Role('TaskRole') do - AssumeRolePolicyDocument ({ - Statement: [ - { - Effect: 'Allow', - Principal: { Service: [ 'ecs-tasks.amazonaws.com' ] }, - Action: [ 'sts:AssumeRole' ] - }, - { - Effect: 'Allow', - Principal: { Service: [ 'ssm.amazonaws.com' ] }, - Action: [ 'sts:AssumeRole' ] - } - ] - }) + AssumeRolePolicyDocument service_assume_role_policy(['ecs-tasks','ssm']) Path '/' - Policies(policies) + Policies(iam_role_policies(iam_policies)) end - + IAM_Role('ExecutionRole') do - AssumeRolePolicyDocument service_role_assume_policy(['ecs-tasks', 'ssm']) + AssumeRolePolicyDocument service_assume_role_policy(['ecs-tasks','ssm']) Path '/' ManagedPolicyArns ["arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"] + if secrets_policy.any? - Policies secrets_policy + Policies iam_role_policies(secrets_policy) end + end end diff --git a/tests/depends_on.test.yaml b/tests/depends_on.test.yaml new file mode 100644 index 0000000..0e0c268 --- /dev/null +++ b/tests/depends_on.test.yaml @@ -0,0 +1,27 @@ +test_metadata: + type: config + name: depends_on + description: test task dependencies + +task_definition: + + nginx: + repo: nginx + image: nginx + depends_on: + db: START + db: + image: postgres + not_essential: true + ports: + - 5432 + +targetgroup: + name: nginx + container: nginx + port: 80 + protocol: http + listener: http + healthcheck: + path: / + code: 200 \ No newline at end of file diff --git a/tests/ec2.test.yaml b/tests/ec2.test.yaml index 10b1e30..b30987d 100644 --- a/tests/ec2.test.yaml +++ b/tests/ec2.test.yaml @@ -1,7 +1,7 @@ test_metadata: type: config - name: fargate - description: Provision a fargate based ecs task + name: ec2 + description: Provision a ec2 based ecs task task_definition: schema: From 5110a85f99dca4297c32e20b163441e86dec9c4a Mon Sep 17 00:00:00 2001 From: Aaron Walker Date: Thu, 1 Apr 2021 14:27:42 +0200 Subject: [PATCH 2/3] adds tests --- .github/workflows/rspec.yaml | 25 +++++ README.md | 26 +++++- ecs-task.cfndsl.rb | 52 ++++++----- spec/default_spec.rb | 26 ++++++ spec/ec2_spec.rb | 58 ++++++++++++ spec/fargate_spec.rb | 57 ++++++++++++ spec/secrets_spec.rb | 176 +++++++++++++++++++++++++++++++++++ spec/spec_helper.rb | 103 ++++++++++++++++++++ tests/default.test.yaml | 4 + 9 files changed, 502 insertions(+), 25 deletions(-) create mode 100644 .github/workflows/rspec.yaml create mode 100644 spec/default_spec.rb create mode 100644 spec/ec2_spec.rb create mode 100644 spec/fargate_spec.rb create mode 100644 spec/secrets_spec.rb create mode 100644 spec/spec_helper.rb create mode 100644 tests/default.test.yaml diff --git a/.github/workflows/rspec.yaml b/.github/workflows/rspec.yaml new file mode 100644 index 0000000..b1ee9a7 --- /dev/null +++ b/.github/workflows/rspec.yaml @@ -0,0 +1,25 @@ +name: cftest + +on: [push, pull_request] + +jobs: + test: + name: test + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: set up ruby 2.7 + uses: actions/setup-ruby@v1 + with: + ruby-version: 2.7.x + - name: install gems + run: gem install cfhighlander rspec + - name: set cfndsl spec + run: cfndsl -u + - name: cftest + run: rspec + env: + AWS_ACCESS_KEY: ${{ secrets.AWS_ACCESS_KEY }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + AWS_REGION: ap-southeast-2 \ No newline at end of file diff --git a/README.md b/README.md index 04d00e7..72d807b 100644 --- a/README.md +++ b/README.md @@ -1 +1,25 @@ -# hl-component-ecs-task \ No newline at end of file +![cftest](https://github.com/theonestack/hl-component-ecs-task/actions/workflows/rspec.yaml/badge.svg) + +### Cfhighlander ECS Task component + +```bash + +# install highlander gem +$ gem install cfhighlander + +# build and validate standalone component +$ cfhighlander cfcompile --validate ecs-task + +``` + +### Parameters + +TBD + +### Configuration options + +TBD + +### Outputs + +TBD \ No newline at end of file diff --git a/ecs-task.cfndsl.rb b/ecs-task.cfndsl.rb index bbaf367..58a6297 100644 --- a/ecs-task.cfndsl.rb +++ b/ecs-task.cfndsl.rb @@ -282,38 +282,42 @@ end task_type = external_parameters.fetch(:task_type, 'EC2') - ECS_TaskDefinition('Task') do - ContainerDefinitions definitions - RequiresCompatibilities [task_type] + unless task_definition.empty? - if external_parameters[:cpu] - Cpu external_parameters[:cpu] - end + ECS_TaskDefinition('Task') do + ContainerDefinitions definitions + RequiresCompatibilities [task_type] - if external_parameters[:memory] - Memory external_parameters[:memory] - end + if external_parameters[:cpu] + Cpu external_parameters[:cpu] + end - if external_parameters[:network_mode] - NetworkMode external_parameters[:network_mode] - end + if external_parameters[:memory] + Memory external_parameters[:memory] + end - if task_volumes.any? - Volumes task_volumes - end + if external_parameters[:network_mode] + NetworkMode external_parameters[:network_mode] + end + + if task_volumes.any? + Volumes task_volumes + end + + unless iam_policies.empty? + TaskRoleArn Ref('TaskRole') + ExecutionRoleArn Ref('ExecutionRole') + end + + Tags task_tags - unless iam_policies.empty? - TaskRoleArn Ref('TaskRole') - ExecutionRoleArn Ref('ExecutionRole') end - Tags task_tags + Output("EcsTaskArn") { + Value(Ref('Task')) + Export FnSub("${EnvironmentName}-#{export}-EcsTaskArn") + } end - Output("EcsTaskArn") { - Value(Ref('Task')) - Export FnSub("${EnvironmentName}-#{export}-EcsTaskArn") - } - end diff --git a/spec/default_spec.rb b/spec/default_spec.rb new file mode 100644 index 0000000..c782456 --- /dev/null +++ b/spec/default_spec.rb @@ -0,0 +1,26 @@ +require 'yaml' + +describe 'compiled component' do + + context 'cftest' do + it 'compiles test' do + expect(system("cfhighlander cftest #{@validate} --tests tests/default.test.yaml")).to be_truthy + end + end + + let(:template) { YAML.load_file("#{File.dirname(__FILE__)}/../out/tests/default/ecs-task.compiled.yaml") } + + context 'Resources' do + it 'has No Task ' do + expect(template["Resources"]['Task']).to eq(nil) + end + + it 'has a Log Group' do + expect(template["Resources"]['LogGroup']).to eq({ + "Type"=>"AWS::Logs::LogGroup", + "Properties"=>{"LogGroupName"=>{"Ref"=>"AWS::StackName"}, "RetentionInDays"=>"7"} + }) + end + end + +end \ No newline at end of file diff --git a/spec/ec2_spec.rb b/spec/ec2_spec.rb new file mode 100644 index 0000000..755c713 --- /dev/null +++ b/spec/ec2_spec.rb @@ -0,0 +1,58 @@ +require 'yaml' + +describe 'compiled component' do + + context 'cftest' do + it 'compiles test' do + expect(system("cfhighlander cftest #{@validate} --tests tests/ec2.test.yaml")).to be_truthy + end + end + + let(:template) { YAML.load_file("#{File.dirname(__FILE__)}/../out/tests/ec2/ecs-task.compiled.yaml") } + + context 'Resource Task' do + let(:properties) { template["Resources"]["Task"]["Properties"] } + + it 'has property RequiresCompatibilities ' do + expect(properties["RequiresCompatibilities"]).to eq(['EC2']) + end + + it 'has property NetworkMode ' do + expect(properties["NetworkMode"]).to eq(nil) + end + + it 'has property CPU ' do + expect(properties["Cpu"]).to eq(nil) + end + + it 'has property Memory ' do + expect(properties["Memory"]).to eq(nil) + end + + it 'has property One container definition ' do + expect(properties["ContainerDefinitions"].count).to eq(1) + expect(properties["ContainerDefinitions"]).to eq([{ + "Image"=>{"Fn::Join"=>["", ["myrepo/", "backend", ":", {"Ref"=>"SchemaTag"}]]}, + "LogConfiguration"=> + { + "LogDriver"=>"awslogs", + "Options"=> { + "awslogs-group"=>{"Ref"=>"LogGroup"}, + "awslogs-region"=>{"Ref"=>"AWS::Region"}, + "awslogs-stream-prefix"=>"schema" + } + }, + "Name"=>"schema" + }]) + end + + it 'has property Tags' do + expect(properties["Tags"]).to eq([ + {"Key"=>"Name", "Value"=>"ecs-task"}, + {"Key"=>"Environment", "Value"=>{"Ref"=>"EnvironmentName"}}, + {"Key"=>"EnvironmentType", "Value"=>{"Ref"=>"EnvironmentType"}}, + {"Key"=>"CostCenter", "Value"=>"TeamA"} + ]) + end + end +end \ No newline at end of file diff --git a/spec/fargate_spec.rb b/spec/fargate_spec.rb new file mode 100644 index 0000000..901d87f --- /dev/null +++ b/spec/fargate_spec.rb @@ -0,0 +1,57 @@ +require 'yaml' + +describe 'compiled component' do + + context 'cftest' do + it 'compiles test' do + expect(system("cfhighlander cftest #{@validate} --tests tests/fargate.test.yaml")).to be_truthy + end + end + + let(:template) { YAML.load_file("#{File.dirname(__FILE__)}/../out/tests/fargate/ecs-task.compiled.yaml") } + + context 'Resource Task' do + let(:properties) { template["Resources"]["Task"]["Properties"] } + + it 'has property RequiresCompatibilities ' do + expect(properties["RequiresCompatibilities"]).to eq(['FARGATE']) + end + + it 'has property NetworkMode ' do + expect(properties["NetworkMode"]).to eq('awsvpc') + end + + it 'has property CPU ' do + expect(properties["Cpu"]).to eq(256) + end + + it 'has property Memory ' do + expect(properties["Memory"]).to eq(512) + end + + it 'has property One container definition ' do + expect(properties["ContainerDefinitions"].count).to eq(1) + expect(properties["ContainerDefinitions"]).to eq([{ + "Image"=>{"Fn::Join"=>["", ["myrepo/", "backend", ":", {"Ref"=>"SchemaTag"}]]}, + "LogConfiguration"=> + { + "LogDriver"=>"awslogs", + "Options"=> { + "awslogs-group"=>{"Ref"=>"LogGroup"}, + "awslogs-region"=>{"Ref"=>"AWS::Region"}, + "awslogs-stream-prefix"=>"schema" + } + }, + "Name"=>"schema" + }]) + end + + it 'has property Tags' do + expect(properties["Tags"]).to eq([ + {"Key"=>"Name", "Value"=>"ecs-task"}, + {"Key"=>"Environment", "Value"=>{"Ref"=>"EnvironmentName"}}, + {"Key"=>"EnvironmentType", "Value"=>{"Ref"=>"EnvironmentType"}} + ]) + end + end +end \ No newline at end of file diff --git a/spec/secrets_spec.rb b/spec/secrets_spec.rb new file mode 100644 index 0000000..f360f02 --- /dev/null +++ b/spec/secrets_spec.rb @@ -0,0 +1,176 @@ +require 'yaml' + +describe 'compiled component' do + + context 'cftest' do + it 'compiles test' do + expect(system("cfhighlander cftest #{@validate} --tests tests/secrets.test.yaml")).to be_truthy + end + end + + let(:template) { YAML.load_file("#{File.dirname(__FILE__)}/../out/tests/secrets/ecs-task.compiled.yaml") } + + context 'Resource Task' do + let(:properties) { template["Resources"]["Task"]["Properties"] } + + it 'has property RequiresCompatibilities ' do + expect(properties["RequiresCompatibilities"]).to eq(['EC2']) + end + + it 'has property NetworkMode ' do + expect(properties["NetworkMode"]).to eq(nil) + end + + it 'has property CPU ' do + expect(properties["Cpu"]).to eq(nil) + end + + it 'has property Memory ' do + expect(properties["Memory"]).to eq(nil) + end + + it 'has property One container definition ' do + expect(properties["ContainerDefinitions"].count).to eq(1) + expect(properties["ContainerDefinitions"]).to eq([{ + "Name"=>"nginx", + "Image"=>{"Fn::Join"=>["", ["nginx/", "nginx", ":", "latest"]]}, + "LogConfiguration"=> { + "LogDriver"=>"awslogs", + "Options"=> { + "awslogs-group"=>{"Ref"=>"LogGroup"}, + "awslogs-region"=>{"Ref"=>"AWS::Region"}, + "awslogs-stream-prefix"=>"nginx" + } + }, + "Secrets"=> [ + { + "Name"=>"APP_KEY", + "ValueFrom" => { + "Fn::Sub" => "arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/nginx/${EnvironmentName}/app/key" + } + }, + { + "Name"=>"APP_SECRET", + "ValueFrom" => { + "Fn::Sub" => "arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/nginx/${EnvironmentName}/app/secret" + } + }, + { + "Name"=>"ACCESSKEY", + "ValueFrom" => { + "Fn::Sub" => "arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:/dont/use/accesskeys" + } + }, + {"Name"=>"SECRETKEY", "ValueFrom"=>{"Ref"=>"EnvironmentName"}}, + { + "Name"=>"API_KEY", + "ValueFrom" => { + "Fn::Sub" => "arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/nginx/${EnvironmentName}/api/key" + } + }, + { + "Name"=>"API_SECRET", + "ValueFrom" => { + "Fn::Sub" => "arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/nginx/${EnvironmentName}/api/secret" + } + } + ] + }]) + end + + + + + it 'has property Tags' do + expect(properties["Tags"]).to eq([ + {"Key"=>"Name", "Value"=>"ecs-task"}, + {"Key"=>"Environment", "Value"=>{"Ref"=>"EnvironmentName"}}, + {"Key"=>"EnvironmentType", "Value"=>{"Ref"=>"EnvironmentType"}} + ]) + end + end + + context 'Resource TaskRole' do + let(:properties) { template["Resources"]["TaskRole"]["Properties"] } + + it 'has Task Role' do + expect(properties).to eq({ + "AssumeRolePolicyDocument" => {"Statement"=>[{"Action"=>"sts:AssumeRole", "Effect"=>"Allow", "Principal"=>{"Service"=>"ecs-tasks.amazonaws.com"}}, {"Action"=>"sts:AssumeRole", "Effect"=>"Allow", "Principal"=>{"Service"=>"ssm.amazonaws.com"}}], "Version"=>"2012-10-17"}, + "Path" => "/", + "Policies" => [{"PolicyDocument"=>{"Statement"=>[{"Action"=>["s3:Get*"], "Effect"=>"Allow", "Resource"=>["*"], "Sid"=>"s3"}]}, "PolicyName"=>"s3"}], + }) + end + end + + context 'Resource Execution Role' do + let(:properties) { template["Resources"]["ExecutionRole"]["Properties"] } + + it 'has Execution Role' do + expect(properties).to eq({ + "AssumeRolePolicyDocument" => { + "Statement"=>[ + { + "Action"=>"sts:AssumeRole", + "Effect"=>"Allow", + "Principal"=>{"Service"=>"ecs-tasks.amazonaws.com"} + }, + { + "Action"=>"sts:AssumeRole", + "Effect"=>"Allow", + "Principal"=>{"Service"=>"ssm.amazonaws.com"} + } + ], + "Version"=>"2012-10-17" + }, + "ManagedPolicyArns" => ["arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"], + "Path" => "/", + "Policies" => [ + { + "PolicyName"=>"ssm-secrets", + "PolicyDocument"=>{ + "Statement"=>[ + { + "Action"=>"ssm:GetParameters", + "Effect"=>"Allow", + "Resource"=>[ + {"Fn::Sub"=>"arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/nginx/${EnvironmentName}/app/key"}, + {"Fn::Sub"=>"arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/nginx/${EnvironmentName}/app/secret"} + ], + "Sid"=>"ssmsecrets" + } + ] + } + }, + { + "PolicyName"=>"secretsmanager", + "PolicyDocument"=>{ + "Statement"=>[ + {"Action"=>"secretsmanager:GetSecretValue", + "Effect"=>"Allow", + "Resource"=>[ + {"Fn::Sub"=>"arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:/dont/use/accesskeys-*"}, + {"Ref"=>"EnvironmentName"} + ], + "Sid"=>"secretsmanager"} + ] + } + }, + { + "PolicyName"=>"ssm-secrets-inline", + "PolicyDocument"=>{ + "Statement"=>[ + {"Action"=>"ssm:GetParameters", + "Effect"=>"Allow", + "Resource"=>[ + {"Fn::Sub"=>"arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/nginx/${EnvironmentName}/api/key"}, + {"Fn::Sub"=>"arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/nginx/${EnvironmentName}/api/secret"} + ], + "Sid"=>"ssmsecretsinline"} + ] + } + } + ] + }) + end + end +end \ No newline at end of file diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000..d32e540 --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,103 @@ +# This file was generated by the `rspec --init` command. Conventionally, all +# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. +# The generated `.rspec` file contains `--require spec_helper` which will cause +# this file to always be loaded, without a need to explicitly require it in any +# files. +# +# Given that it is always loaded, you are encouraged to keep this file as +# light-weight as possible. Requiring heavyweight dependencies from this file +# will add to the boot time of your test suite on EVERY test run, even for an +# individual file that may not need all of that loaded. Instead, consider making +# a separate helper file that requires the additional dependencies and performs +# the additional setup, and require it from the spec files that actually need +# it. +# +# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration +RSpec.configure do |config| + # rspec-expectations config goes here. You can use an alternate + # assertion/expectation library such as wrong or the stdlib/minitest + # assertions if you prefer. + + config.before(:context) { @validate = ENV['TRAVIS_PULL_REQUEST'] ? '--no-validate' : '--validate' } + + config.expect_with :rspec do |expectations| + # This option will default to `true` in RSpec 4. It makes the `description` + # and `failure_message` of custom matchers include text for helper methods + # defined using `chain`, e.g.: + # be_bigger_than(2).and_smaller_than(4).description + # # => "be bigger than 2 and smaller than 4" + # ...rather than: + # # => "be bigger than 2" + expectations.include_chain_clauses_in_custom_matcher_descriptions = true + end + + # rspec-mocks config goes here. You can use an alternate test double + # library (such as bogus or mocha) by changing the `mock_with` option here. + config.mock_with :rspec do |mocks| + # Prevents you from mocking or stubbing a method that does not exist on + # a real object. This is generally recommended, and will default to + # `true` in RSpec 4. + mocks.verify_partial_doubles = true + end + + # This option will default to `:apply_to_host_groups` in RSpec 4 (and will + # have no way to turn it off -- the option exists only for backwards + # compatibility in RSpec 3). It causes shared context metadata to be + # inherited by the metadata hash of host groups and examples, rather than + # triggering implicit auto-inclusion in groups with matching metadata. + config.shared_context_metadata_behavior = :apply_to_host_groups + +# The settings below are suggested to provide a good initial experience +# with RSpec, but feel free to customize to your heart's content. +=begin + # This allows you to limit a spec run to individual examples or groups + # you care about by tagging them with `:focus` metadata. When nothing + # is tagged with `:focus`, all examples get run. RSpec also provides + # aliases for `it`, `describe`, and `context` that include `:focus` + # metadata: `fit`, `fdescribe` and `fcontext`, respectively. + config.filter_run_when_matching :focus + + # Allows RSpec to persist some state between runs in order to support + # the `--only-failures` and `--next-failure` CLI options. We recommend + # you configure your source control system to ignore this file. + config.example_status_persistence_file_path = "spec/examples.txt" + + # Limits the available syntax to the non-monkey patched syntax that is + # recommended. For more details, see: + # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/ + # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ + # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode + config.disable_monkey_patching! + + # This setting enables warnings. It's recommended, but in some cases may + # be too noisy due to issues in dependencies. + config.warnings = true + + # Many RSpec users commonly either run the entire suite or an individual + # file, and it's useful to allow more verbose output when running an + # individual spec file. + if config.files_to_run.one? + # Use the documentation formatter for detailed output, + # unless a formatter has already been configured + # (e.g. via a command-line flag). + config.default_formatter = "doc" + end + + # Print the 10 slowest examples and example groups at the + # end of the spec run, to help surface which specs are running + # particularly slow. + config.profile_examples = 10 + + # Run specs in random order to surface order dependencies. If you find an + # order dependency and want to debug it, you can fix the order by providing + # the seed, which is printed after each run. + # --seed 1234 + config.order = :random + + # Seed global randomization in this process using the `--seed` CLI option. + # Setting this allows you to use `--seed` to deterministically reproduce + # test failures related to randomization by passing the same `--seed` value + # as the one that triggered the failure. + Kernel.srand config.seed +=end +end diff --git a/tests/default.test.yaml b/tests/default.test.yaml new file mode 100644 index 0000000..613991e --- /dev/null +++ b/tests/default.test.yaml @@ -0,0 +1,4 @@ +test_metadata: + type: config + name: default + description: default \ No newline at end of file From cfe9ae1ea356237ca0200449d1adbce71223b95b Mon Sep 17 00:00:00 2001 From: Aaron Walker Date: Thu, 1 Apr 2021 14:34:03 +0200 Subject: [PATCH 3/3] remove travis ci --- .travis.yml | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 806532c..0000000 --- a/.travis.yml +++ /dev/null @@ -1,10 +0,0 @@ -language: ruby -rvm: - - 2.5 -install: - - gem install cfhighlander cfn-nag -before_script: - - cfndsl -u 2.21.0 -script: - - if [ "${TRAVIS_PULL_REQUEST}" != "false" ]; then cfhighlander cftest --no-validate; else cfhighlander cftest; fi - - cfn_nag_scan -i out/tests \ No newline at end of file