Skip to content

feat(aws): Add check for malicious AMI detection #352

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Mar 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/test-rego.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ jobs:
- name: Setup Regal
uses: StyraInc/setup-regal@33a142b1189004e0f14bf42b15972c67eecce776 # v1
with:
version: 0.29
version: 0.29.0

- name: Lint Rego
run: make lint-rego
Expand Down
15 changes: 15 additions & 0 deletions avd_docs/aws/ami/AVD-AWS-0344/docs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@

AWS AMI data source should specify owners to avoid using unverified AMIs.
The owners field helps ensure you're using AMIs from known and trusted sources.


### Impact
<!-- Add Impact here -->

<!-- DO NOT CHANGE -->
{{ remediationActions }}

### Links
- https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ami


37 changes: 37 additions & 0 deletions checks/cloud/aws/ec2/specify_ami_owners.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# METADATA
# title: AWS AMI data source should specify owners
# description: |
# AWS AMI data source should specify owners to avoid using unverified AMIs.
# The owners field helps ensure you're using AMIs from known and trusted sources.
# scope: package
# schemas:
# - input: schema["cloud"]
# related_resources:
# - https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ami
# custom:
# id: AVD-AWS-0344
# avd_id: AVD-AWS-0344
# provider: aws
# service: ami
# severity: LOW
# short_code: ensure-ami-has-owners
# recommended_action: Specify the owners field in the AWS AMI data source configuration
# input:
# selector:
# - type: cloud
# subtypes:
# - service: ec2
# provider: aws
package builtin.aws.ec2.aws0344

import rego.v1

deny contains res if {
some ami in input.aws.ec2.requestedamis
owners_not_specified(ami)
res := result.new("AWS AMI data source should specify owners to ensure AMIs come from trusted sources", ami)
}

owners_not_specified(ami) if not ami.owners

owners_not_specified(ami) if count(ami.owners) == 0
22 changes: 22 additions & 0 deletions checks/cloud/aws/ec2/specify_ami_owners.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
terraform:
good_examples:
- |-
data "aws_ami" "example" {
most_recent = true
owners = ["099720109477"] # Canonical

filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
}
}
bad_examples:
- |-
data "aws_ami" "example" {
most_recent = true

filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
}
}
19 changes: 19 additions & 0 deletions checks/cloud/aws/ec2/specify_ami_owners_test.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package builtin.aws.ec2.aws0344_test

import rego.v1

import data.builtin.aws.ec2.aws0344 as check
import data.lib.test

test_deny_missing_owners if {
msg := "AWS AMI data source should specify owners to ensure AMIs come from trusted sources"
test.assert_equal_message(msg, check.deny) with input as {"aws": {"ec2": {"requestedamis": [{}]}}}
}

test_allow_valid_owners if {
test.assert_empty(check.deny) with input as {"aws": {"ec2": {"requestedamis": [{"owners": ["self"]}]}}}
}

test_allow_valid_multiple_owners if {
test.assert_empty(check.deny) with input as {"aws": {"ec2": {"requestedamis": [{"owners": ["amazon", "self"]}]}}}
}
2 changes: 1 addition & 1 deletion examples/cloudformation/ensure_required_tags.rego
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ deny contains res if {
some resource in input.Resources
not resource.Tags
res := result.new(
sprintf("Resource $q does not have required tags %v", [resource.Type, required_tags]),
sprintf("Resource %q does not have required tags %v", [resource.Type, required_tags]),
{},
)
}
Expand Down
206 changes: 107 additions & 99 deletions go.mod

Large diffs are not rendered by default.

1,209 changes: 958 additions & 251 deletions go.sum

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions integration/check_examples_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,8 @@ func pushBundle(t *testing.T, ctx context.Context, path string, image string) {
require.NoError(t, c.Terminate(ctx))
}

// TODO: AVD-AWS-0344 check is excluded because its input does not match the scheme of older versions of Trivy.
// Remove it for the latest version after this issue is resolved.
var excludedChecks = map[string][]string{
// Excluded for all versions, as these checks are only for documentation and lack implementation.
"": {
Expand All @@ -153,6 +155,13 @@ var excludedChecks = map[string][]string{
"0.57.1": {
// After version 0.57.1, the bug with the field type was fixed and the example was updated. See: https://github.com/aquasecurity/trivy/pull/7995
"AVD-AWS-0036",
"AVD-AWS-0344",
},
"0.58.1": {
"AVD-AWS-0344",
},
"latest": {
"AVD-AWS-0344",
},
}

Expand Down
2 changes: 1 addition & 1 deletion test/rego/aws_ecr_test.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package test

import (
"github.com/aquasecurity/iamgo"
"github.com/aquasecurity/trivy/pkg/iac/providers/aws"
"github.com/aquasecurity/trivy/pkg/iac/providers/aws/ecr"
"github.com/aquasecurity/trivy/pkg/iac/providers/aws/iam"
"github.com/aquasecurity/trivy/pkg/iac/state"
trivyTypes "github.com/aquasecurity/trivy/pkg/iac/types"
"github.com/liamg/iamgo"
)

func init() {
Expand Down
2 changes: 1 addition & 1 deletion test/rego/aws_iam_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ package test
import (
"time"

"github.com/aquasecurity/iamgo"
"github.com/aquasecurity/trivy/pkg/iac/providers/aws"
"github.com/aquasecurity/trivy/pkg/iac/providers/aws/iam"
"github.com/aquasecurity/trivy/pkg/iac/state"
trivyTypes "github.com/aquasecurity/trivy/pkg/iac/types"
"github.com/liamg/iamgo"
)

func init() {
Expand Down
2 changes: 1 addition & 1 deletion test/rego/aws_sqs_test.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package test

import (
"github.com/aquasecurity/iamgo"
"github.com/aquasecurity/trivy/pkg/iac/providers/aws"
"github.com/aquasecurity/trivy/pkg/iac/providers/aws/iam"
"github.com/aquasecurity/trivy/pkg/iac/providers/aws/sqs"
"github.com/aquasecurity/trivy/pkg/iac/state"
trivyTypes "github.com/aquasecurity/trivy/pkg/iac/types"
"github.com/liamg/iamgo"
)

func init() {
Expand Down
3 changes: 1 addition & 2 deletions test/rego/rego_checks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ func addTests(tc testCases) {

func TestRegoChecks(t *testing.T) {
regoScanner := rego.NewScanner(
trivyTypes.SourceCloud,
rego.WithFrameworks(framework.CIS_AWS_1_2, framework.CIS_AWS_1_4, framework.Default),
rego.WithPolicyDirs("."),
rego.WithEmbeddedLibraries(true),
Expand All @@ -57,7 +56,7 @@ func TestRegoChecks(t *testing.T) {
}

func scanState(t *testing.T, regoScanner *rego.Scanner, s state.State, checkID string, expected bool) {
results, err := regoScanner.ScanInput(context.TODO(), rego.Input{
results, err := regoScanner.ScanInput(context.TODO(), trivyTypes.SourceCloud, rego.Input{
Contents: s.ToRego(),
})
require.NoError(t, err)
Expand Down
Loading