Skip to content
Draft
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
3 changes: 2 additions & 1 deletion pkg/iac/adapters/cloudformation/aws/athena/athena_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ Resources:
WorkGroupConfiguration:
EnforceWorkGroupConfiguration: true
ResultConfiguration:
EncryptionOption: SSE_KMS
EncryptionConfiguration:
EncryptionOption: SSE_KMS
`,
expected: athena.Athena{
Workgroups: []athena.Workgroup{
Expand Down
4 changes: 2 additions & 2 deletions pkg/iac/adapters/cloudformation/aws/ec2/launch_template.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ func getLaunchTemplates(file parser.FileContext) (templates []ec2.LaunchTemplate
func adaptLaunchTemplate(r *parser.Resource) ec2.LaunchTemplate {
launchTemplate := ec2.LaunchTemplate{
Metadata: r.Metadata(),
Name: r.GetStringProperty("LaunchTemplateName", ""),
Name: r.GetStringProperty("LaunchTemplateName"),
Instance: ec2.Instance{
Metadata: r.Metadata(),
MetadataOptions: ec2.MetadataOptions{
Expand All @@ -39,7 +39,7 @@ func adaptLaunchTemplate(r *parser.Resource) ec2.LaunchTemplate {
}
}

launchTemplate.Instance.UserData = data.GetStringProperty("UserData", "")
launchTemplate.Instance.UserData = data.GetStringProperty("UserData")

blockDevices := getBlockDevices(r)
for i, device := range blockDevices {
Expand Down
4 changes: 2 additions & 2 deletions pkg/iac/adapters/cloudformation/aws/ecr/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,15 @@ func getRepositories(ctx parser.FileContext) (repositories []ecr.Repository) {
if imageScanningProp := r.GetProperty("ImageScanningConfiguration"); imageScanningProp.IsNotNil() {
repository.ImageScanning = ecr.ImageScanning{
Metadata: imageScanningProp.Metadata(),
ScanOnPush: imageScanningProp.GetBoolProperty("ScanOnPush", false),
ScanOnPush: imageScanningProp.GetBoolProperty("ScanOnPush"),
}
}

if encProp := r.GetProperty("EncryptionConfiguration"); encProp.IsNotNil() {
repository.Encryption = ecr.Encryption{
Metadata: encProp.Metadata(),
Type: encProp.GetStringProperty("EncryptionType", ecr.EncryptionTypeAES256),
KMSKeyID: encProp.GetStringProperty("KmsKey", ""),
KMSKeyID: encProp.GetStringProperty("KmsKey"),
}
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/iac/adapters/cloudformation/aws/elb/loadbalancer.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func getListeners(lbr *parser.Resource, ctx parser.FileContext) (listeners []elb
listener := elb.Listener{
Metadata: r.Metadata(),
Protocol: r.GetStringProperty("Protocol", "HTTP"),
TLSPolicy: r.GetStringProperty("SslPolicy", ""),
TLSPolicy: r.GetStringProperty("SslPolicy"),
DefaultActions: getDefaultListenerActions(r),
}

Expand Down
8 changes: 4 additions & 4 deletions pkg/iac/adapters/cloudformation/aws/msk/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ func getClusters(ctx parser.FileContext) (clusters []msk.Cluster) {
if encAtRestProp := r.GetProperty("EncryptionInfo.EncryptionAtRest"); encAtRestProp.IsNotNil() {
cluster.EncryptionAtRest = msk.EncryptionAtRest{
Metadata: encAtRestProp.Metadata(),
KMSKeyARN: encAtRestProp.GetStringProperty("DataVolumeKMSKeyId", ""),
KMSKeyARN: encAtRestProp.GetStringProperty("DataVolumeKMSKeyId"),
Enabled: iacTypes.BoolDefault(true, encAtRestProp.Metadata()),
}
}
Expand All @@ -61,15 +61,15 @@ func getClusters(ctx parser.FileContext) (clusters []msk.Cluster) {
cluster.Logging.Broker.Metadata = brokerLoggingProp.Metadata()
if s3Prop := brokerLoggingProp.GetProperty("S3"); s3Prop.IsNotNil() {
cluster.Logging.Broker.S3.Metadata = s3Prop.Metadata()
cluster.Logging.Broker.S3.Enabled = s3Prop.GetBoolProperty("Enabled", false)
cluster.Logging.Broker.S3.Enabled = s3Prop.GetBoolProperty("Enabled")
}
if cwProp := brokerLoggingProp.GetProperty("CloudWatchLogs"); cwProp.IsNotNil() {
cluster.Logging.Broker.Cloudwatch.Metadata = cwProp.Metadata()
cluster.Logging.Broker.Cloudwatch.Enabled = cwProp.GetBoolProperty("Enabled", false)
cluster.Logging.Broker.Cloudwatch.Enabled = cwProp.GetBoolProperty("Enabled")
}
if fhProp := brokerLoggingProp.GetProperty("Firehose"); fhProp.IsNotNil() {
cluster.Logging.Broker.Firehose.Metadata = fhProp.Metadata()
cluster.Logging.Broker.Firehose.Enabled = fhProp.GetBoolProperty("Enabled", false)
cluster.Logging.Broker.Firehose.Enabled = fhProp.GetBoolProperty("Enabled")
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions pkg/iac/adapters/cloudformation/aws/rds/instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ func getClustersAndInstances(ctx parser.FileContext) ([]rds.Cluster, []rds.Insta
PublicAccess: r.GetBoolProperty("PubliclyAccessible", true),
Engine: r.GetStringProperty("Engine"),
IAMAuthEnabled: r.GetBoolProperty("EnableIAMDatabaseAuthentication"),
DeletionProtection: r.GetBoolProperty("DeletionProtection", false),
DeletionProtection: r.GetBoolProperty("DeletionProtection"),
DBInstanceArn: r.GetStringProperty("DBInstanceArn"),
StorageEncrypted: r.GetBoolProperty("StorageEncrypted", false),
StorageEncrypted: r.GetBoolProperty("StorageEncrypted"),
DBInstanceIdentifier: r.GetStringProperty("DBInstanceIdentifier"),
DBParameterGroups: getDBParameterGroups(ctx, r),
TagList: getTagList(r),
Expand Down
2 changes: 1 addition & 1 deletion pkg/iac/adapters/cloudformation/aws/redshift/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func getClusters(ctx parser.FileContext) (clusters []redshift.Cluster) {
Metadata: r.Metadata(),
Port: r.GetIntProperty("Endpoint.Port"),
},
SubnetGroupName: r.GetStringProperty("ClusterSubnetGroupName", ""),
SubnetGroupName: r.GetStringProperty("ClusterSubnetGroupName"),
}

clusters = append(clusters, cluster)
Expand Down
4 changes: 2 additions & 2 deletions pkg/iac/adapters/cloudformation/aws/sam/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ func getApis(cfFile parser.FileContext) (apis []sam.API) {
for _, r := range apiResources {
api := sam.API{
Metadata: r.Metadata(),
Name: r.GetStringProperty("Name", ""),
Name: r.GetStringProperty("Name"),
TracingEnabled: r.GetBoolProperty("TracingEnabled"),
DomainConfiguration: getDomainConfiguration(r),
AccessLogging: getAccessLogging(r),
Expand Down Expand Up @@ -70,7 +70,7 @@ func getAccessLogging(r *parser.Resource) sam.AccessLogging {
if access := r.GetProperty("AccessLogSetting"); access.IsNotNil() {
logging = sam.AccessLogging{
Metadata: access.Metadata(),
CloudwatchLogGroupARN: access.GetStringProperty("DestinationArn", ""),
CloudwatchLogGroupARN: access.GetStringProperty("DestinationArn"),
}
}

Expand Down
4 changes: 2 additions & 2 deletions pkg/iac/adapters/cloudformation/aws/sam/http_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ func getHttpApis(cfFile parser.FileContext) (apis []sam.HttpAPI) {
for _, r := range apiResources {
api := sam.HttpAPI{
Metadata: r.Metadata(),
Name: r.GetStringProperty("Name", ""),
Name: r.GetStringProperty("Name"),
DomainConfiguration: getDomainConfiguration(r),
AccessLogging: getAccessLoggingV2(r),
DefaultRouteSettings: getRouteSettings(r),
Expand All @@ -34,7 +34,7 @@ func getAccessLoggingV2(r *parser.Resource) sam.AccessLogging {
if access := r.GetProperty("AccessLogSettings"); access.IsNotNil() {
logging = sam.AccessLogging{
Metadata: access.Metadata(),
CloudwatchLogGroupARN: access.GetStringProperty("DestinationArn", ""),
CloudwatchLogGroupARN: access.GetStringProperty("DestinationArn"),
}
}

Expand Down
99 changes: 16 additions & 83 deletions pkg/iac/scanners/cloudformation/parser/property.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,64 +226,33 @@ func (p *Property) resolveValue() (*Property, bool) {
}

func (p *Property) GetStringProperty(path string, defaultValue ...string) iacTypes.StringValue {
defVal := ""
if len(defaultValue) > 0 {
defVal = defaultValue[0]
}

if p.IsUnresolved() {
return iacTypes.StringUnresolvable(p.Metadata())
}

prop := p.GetProperty(path)
if prop.IsNotString() {
return p.StringDefault(defVal)
}
return prop.AsStringValue()
return p.GetProperty(path).AsStringValue(firstOrZero(defaultValue))
}

func (p *Property) StringDefault(defaultValue string) iacTypes.StringValue {
return iacTypes.StringDefault(defaultValue, p.Metadata())
}

func (p *Property) GetBoolProperty(path string, defaultValue ...bool) iacTypes.BoolValue {
defVal := false
if len(defaultValue) > 0 {
defVal = defaultValue[0]
}

if p.IsUnresolved() {
return iacTypes.BoolUnresolvable(p.Metadata())
}

prop := p.GetProperty(path)

if prop.isFunction() {
prop, _ = prop.resolveValue()
}

if prop.IsNotBool() {
return p.inferBool(prop, defVal)
}
return prop.AsBoolValue()
return prop.AsBoolValue(firstOrZero(defaultValue))
}

func (p *Property) GetIntProperty(path string, defaultValue ...int) iacTypes.IntValue {
defVal := 0
if len(defaultValue) > 0 {
defVal = defaultValue[0]
}

if p.IsUnresolved() {
return iacTypes.IntUnresolvable(p.Metadata())
}

prop := p.GetProperty(path)

if prop.IsNotInt() {
return p.IntDefault(defVal)
}
return prop.AsIntValue()
return p.GetProperty(path).AsIntValue(firstOrZero(defaultValue))
}

func (p *Property) BoolDefault(defaultValue bool) iacTypes.BoolValue {
Expand All @@ -294,6 +263,10 @@ func (p *Property) IntDefault(defaultValue int) iacTypes.IntValue {
return iacTypes.IntDefault(defaultValue, p.Metadata())
}

func (p *Property) nullProperty() *Property {
return &Property{rng: p.rng, parentRange: p.parentRange, logicalId: p.logicalId}
}

func (p *Property) GetProperty(path string) *Property {
pathParts := strings.Split(path, ".")

Expand All @@ -305,29 +278,23 @@ func (p *Property) GetProperty(path string) *Property {
}

if property.IsNotMap() {
return nil
return property.nullProperty()
}

for n, p := range property.AsMap() {
if n == first {
property = p
break
}
child, ok := property.AsMap()[first]
if !ok {
return property.nullProperty()
}

if len(pathParts) == 1 || property == nil {
return property
}

if nestedProperty := property.GetProperty(strings.Join(pathParts[1:], ".")); nestedProperty != nil {
if nestedProperty.isFunction() {
resolved, _ := nestedProperty.resolveValue()
if len(pathParts) == 1 {
if child.isFunction() {
resolved, _ := child.resolveValue()
return resolved
}
return nestedProperty
return child
}

return &Property{}
return child.GetProperty(strings.Join(pathParts[1:], "."))
}

func (p *Property) deriveResolved(propType cftypes.CfType, propValue any) *Property {
Expand All @@ -341,40 +308,6 @@ func (p *Property) ParentRange() iacTypes.Range {
return p.parentRange
}

func (p *Property) inferBool(prop *Property, defaultValue bool) iacTypes.BoolValue {
if prop.IsString() {
if prop.EqualTo("true", IgnoreCase) {
return iacTypes.Bool(true, prop.Metadata())
}
if prop.EqualTo("yes", IgnoreCase) {
return iacTypes.Bool(true, prop.Metadata())
}
if prop.EqualTo("1", IgnoreCase) {
return iacTypes.Bool(true, prop.Metadata())
}
if prop.EqualTo("false", IgnoreCase) {
return iacTypes.Bool(false, prop.Metadata())
}
if prop.EqualTo("no", IgnoreCase) {
return iacTypes.Bool(false, prop.Metadata())
}
if prop.EqualTo("0", IgnoreCase) {
return iacTypes.Bool(false, prop.Metadata())
}
}

if prop.IsInt() {
if prop.EqualTo(0) {
return iacTypes.Bool(false, prop.Metadata())
}
if prop.EqualTo(1) {
return iacTypes.Bool(true, prop.Metadata())
}
}

return p.BoolDefault(defaultValue)
}

func (p *Property) String() string {
r := ""
switch p.Type {
Expand Down
49 changes: 40 additions & 9 deletions pkg/iac/scanners/cloudformation/parser/property_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,17 @@ import (

"github.com/aquasecurity/trivy/pkg/iac/scanners/cloudformation/cftypes"
iacTypes "github.com/aquasecurity/trivy/pkg/iac/types"
"github.com/aquasecurity/trivy/pkg/set"
)

func firstOrZero[T any](values []T) T {
if len(values) > 0 {
return values[0]
}
var zero T
return zero
}

func (p *Property) IsNil() bool {
return p == nil || p.Value == nil
}
Expand Down Expand Up @@ -92,10 +101,16 @@ func (p *Property) AsString() string {
return p.Value.(string)
}

func (p *Property) AsStringValue() iacTypes.StringValue {
if p.unresolved {
func (p *Property) AsStringValue(defaultValue ...string) iacTypes.StringValue {
if p.IsNil() {
return p.StringDefault(firstOrZero(defaultValue))
}
if p.IsUnresolved() {
return iacTypes.StringUnresolvable(p.Metadata())
}
if !p.IsString() {
return p.StringDefault(firstOrZero(defaultValue))
}
return iacTypes.StringExplicit(p.AsString(), p.Metadata())
}

Expand All @@ -116,28 +131,44 @@ func (p *Property) AsInt() int {
return p.Value.(int)
}

func (p *Property) AsIntValue() iacTypes.IntValue {
if p.unresolved {
func (p *Property) AsIntValue(defaultValue ...int) iacTypes.IntValue {
if p.IsNil() {
return p.IntDefault(firstOrZero(defaultValue))
}
if p.IsUnresolved() {
return iacTypes.IntUnresolvable(p.Metadata())
}
if !p.IsInt() {
return p.IntDefault(firstOrZero(defaultValue))
}
return iacTypes.IntExplicit(p.AsInt(), p.Metadata())
}

var boolTrueStrings = set.NewCaseInsensitive("true", "yes", "1")

func (p *Property) AsBool() bool {
if p.isFunction() {
if prop, success := p.resolveValue(); success && prop != p {
return prop.AsBool()
}
return false
}
if !p.IsBool() {
return false
switch p.Type {
case cftypes.Bool:
return p.Value.(bool)
case cftypes.String:
return boolTrueStrings.Contains(p.AsString())
case cftypes.Int:
return p.AsInt() != 0
}
return p.Value.(bool)
return false
}

func (p *Property) AsBoolValue() iacTypes.BoolValue {
if p.unresolved {
func (p *Property) AsBoolValue(defaultValue ...bool) iacTypes.BoolValue {
if p.IsNil() {
return p.BoolDefault(firstOrZero(defaultValue))
}
if p.IsUnresolved() {
return iacTypes.BoolUnresolvable(p.Metadata())
}
return iacTypes.Bool(p.AsBool(), p.Metadata())
Expand Down
Loading
Loading