|
| 1 | +require 'json' |
| 2 | +require 'net/http' |
| 3 | +require 'uri' |
| 4 | + |
| 5 | +def text_block_from(finding_counts) |
| 6 | + if finding_counts.fetch('CRITICAL', 0) != 0 |
| 7 | + { 'color' => 'danger', 'icon' => ':red_circle:' } |
| 8 | + elsif finding_counts.fetch('HIGH', 0) != 0 |
| 9 | + { 'color' => 'warning', 'icon' => ':large_orange_diamond:' } |
| 10 | + else |
| 11 | + { 'color' => 'good', 'icon' => ':green_heart:' } |
| 12 | + end |
| 13 | +end |
| 14 | + |
| 15 | +def build_slack_message(event) |
| 16 | + channel = ENV.fetch('CHANNEL') |
| 17 | + |
| 18 | + account_id = event.fetch('account') |
| 19 | + detail = event.fetch('detail') |
| 20 | + region = event.fetch('region') |
| 21 | + repository_name = detail.fetch('repository-name') |
| 22 | + severity_counts = detail.fetch('finding-severity-counts') |
| 23 | + image_digest = detail.fetch('image-digest') |
| 24 | + |
| 25 | + message = "*ECR Image Scan findings | #{region} | Account ID:#{account_id}*" |
| 26 | + text_properties = text_block_from(severity_counts) |
| 27 | + |
| 28 | + { |
| 29 | + 'username' => 'Amazon ECR', |
| 30 | + 'channels' => channel, |
| 31 | + 'icon_emoji' => ':ecr:', |
| 32 | + 'text' => message, |
| 33 | + 'attachments' => [ |
| 34 | + { |
| 35 | + 'fallback' => 'AmazonECR Image Scan Findings Description.', |
| 36 | + 'color' => text_properties.fetch('color'), |
| 37 | + 'title' => "#{text_properties.fetch('icon')} #{repository_name}:#{detail.fetch('image-tags', [])[0]}", |
| 38 | + 'title_link' => "https://#{region}.console.aws.amazon.com/ecr/repositories/#{repository_name}/_/image/#{image_digest}/scan-results?region=#{region}", |
| 39 | + 'text' => "Image Scan Completed at #{event.fetch('time')}", |
| 40 | + 'fields' => severity_counts.map do |severity_level, count| |
| 41 | + { 'title' => severity_level.capitalize, 'value' => count, 'short' => true } |
| 42 | + end |
| 43 | + } |
| 44 | + ] |
| 45 | + } |
| 46 | +end |
| 47 | + |
| 48 | +def lambda_handler(event:, context:) |
| 49 | + # Sample responses |
| 50 | + # { |
| 51 | + # "version": "0", |
| 52 | + # "id": "85fc3613-e913-7fc4-a80c-a3753e4aa9ae", |
| 53 | + # "detail-type": "ECR Image Scan", |
| 54 | + # "source": "aws.ecr", |
| 55 | + # "account": "123456789012", |
| 56 | + # "time": "2019-10-29T02:36:48Z", |
| 57 | + # "region": "us-east-1", |
| 58 | + # "resources": [ |
| 59 | + # "arn:aws:ecr:us-east-1:123456789012:repository/my-repo" |
| 60 | + # ], |
| 61 | + # "detail": { |
| 62 | + # "scan-status": "COMPLETE", |
| 63 | + # "repository-name": "my-repo", |
| 64 | + # "finding-severity-counts": { |
| 65 | + # "CRITICAL": 10, |
| 66 | + # "MEDIUM": 9 |
| 67 | + # }, |
| 68 | + # "image-digest": "sha256:7f5b2640fe6fb4f46592dfd3410c4a79dac4f89e4782432e0378abcd1234", |
| 69 | + # "image-tags": ["commit-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"] |
| 70 | + # } |
| 71 | + # } |
| 72 | + # |
| 73 | + slack_message = build_slack_message(event) |
| 74 | + uri = URI(ENV.fetch('WEBHOOK_URL')) |
| 75 | + req = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json') |
| 76 | + req.body = slack_message.to_json |
| 77 | + |
| 78 | + begin |
| 79 | + Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http| |
| 80 | + http.request(req) |
| 81 | + end |
| 82 | + puts('Message posted.') |
| 83 | + rescue StandardError => e |
| 84 | + puts("Request failed: #{e.message}") |
| 85 | + end |
| 86 | +end |
0 commit comments