github.com/devseccon/trivy@v0.47.1-0.20231123133102-bd902a0bd996/pkg/cloud/aws/commands/run_test.go (about) 1 package commands 2 3 import ( 4 "bytes" 5 "context" 6 "github.com/devseccon/trivy/pkg/clock" 7 "os" 8 "path/filepath" 9 "testing" 10 "time" 11 12 "github.com/stretchr/testify/assert" 13 "github.com/stretchr/testify/require" 14 15 defsecTypes "github.com/aquasecurity/defsec/pkg/types" 16 dbTypes "github.com/aquasecurity/trivy-db/pkg/types" 17 "github.com/devseccon/trivy/pkg/compliance/spec" 18 "github.com/devseccon/trivy/pkg/flag" 19 ) 20 21 const expectedS3ScanResult = `{ 22 "CreatedAt": "2021-08-25T12:20:30.000000005Z", 23 "ArtifactName": "12345678", 24 "ArtifactType": "aws_account", 25 "Metadata": { 26 "ImageConfig": { 27 "architecture": "", 28 "created": "0001-01-01T00:00:00Z", 29 "os": "", 30 "rootfs": { 31 "type": "", 32 "diff_ids": null 33 }, 34 "config": {} 35 } 36 }, 37 "Results": [ 38 { 39 "Target": "arn:aws:s3:::examplebucket", 40 "Class": "config", 41 "Type": "cloud", 42 "MisconfSummary": { 43 "Successes": 1, 44 "Failures": 8, 45 "Exceptions": 0 46 }, 47 "Misconfigurations": [ 48 { 49 "Type": "AWS", 50 "ID": "AVD-AWS-0086", 51 "AVDID": "AVD-AWS-0086", 52 "Title": "S3 Access block should block public ACL", 53 "Description": "S3 buckets should block public ACLs on buckets and any objects they contain. By blocking, PUTs with fail if the object has any public ACL a.", 54 "Message": "No public access block so not blocking public acls", 55 "Resolution": "Enable blocking any PUT calls with a public ACL specified", 56 "Severity": "HIGH", 57 "PrimaryURL": "https://avd.aquasec.com/misconfig/avd-aws-0086", 58 "References": [ 59 "https://avd.aquasec.com/misconfig/avd-aws-0086" 60 ], 61 "Status": "FAIL", 62 "Layer": {}, 63 "CauseMetadata": { 64 "Resource": "arn:aws:s3:::examplebucket", 65 "Provider": "aws", 66 "Service": "s3", 67 "Code": { 68 "Lines": null 69 } 70 } 71 }, 72 { 73 "Type": "AWS", 74 "ID": "AVD-AWS-0087", 75 "AVDID": "AVD-AWS-0087", 76 "Title": "S3 Access block should block public policy", 77 "Description": "S3 bucket policy should have block public policy to prevent users from putting a policy that enable public access.", 78 "Message": "No public access block so not blocking public policies", 79 "Resolution": "Prevent policies that allow public access being PUT", 80 "Severity": "HIGH", 81 "PrimaryURL": "https://avd.aquasec.com/misconfig/avd-aws-0087", 82 "References": [ 83 "https://avd.aquasec.com/misconfig/avd-aws-0087" 84 ], 85 "Status": "FAIL", 86 "Layer": {}, 87 "CauseMetadata": { 88 "Resource": "arn:aws:s3:::examplebucket", 89 "Provider": "aws", 90 "Service": "s3", 91 "Code": { 92 "Lines": null 93 } 94 } 95 }, 96 { 97 "Type": "AWS", 98 "ID": "AVD-AWS-0088", 99 "AVDID": "AVD-AWS-0088", 100 "Title": "Unencrypted S3 bucket.", 101 "Description": "S3 Buckets should be encrypted to protect the data that is stored within them if access is compromised.", 102 "Message": "Bucket does not have encryption enabled", 103 "Resolution": "Configure bucket encryption", 104 "Severity": "HIGH", 105 "PrimaryURL": "https://avd.aquasec.com/misconfig/avd-aws-0088", 106 "References": [ 107 "https://avd.aquasec.com/misconfig/avd-aws-0088" 108 ], 109 "Status": "FAIL", 110 "Layer": {}, 111 "CauseMetadata": { 112 "Resource": "arn:aws:s3:::examplebucket", 113 "Provider": "aws", 114 "Service": "s3", 115 "Code": { 116 "Lines": null 117 } 118 } 119 }, 120 { 121 "Type": "AWS", 122 "ID": "AVD-AWS-0090", 123 "AVDID": "AVD-AWS-0090", 124 "Title": "S3 Data should be versioned", 125 "Description": "Versioning in Amazon S3 is a means of keeping multiple variants of an object in the same bucket. \nYou can use the S3 Versioning feature to preserve, retrieve, and restore every version of every object stored in your buckets. \nWith versioning you can recover more easily from both unintended user actions and application failures.", 126 "Message": "Bucket does not have versioning enabled", 127 "Resolution": "Enable versioning to protect against accidental/malicious removal or modification", 128 "Severity": "MEDIUM", 129 "PrimaryURL": "https://avd.aquasec.com/misconfig/avd-aws-0090", 130 "References": [ 131 "https://avd.aquasec.com/misconfig/avd-aws-0090" 132 ], 133 "Status": "FAIL", 134 "Layer": {}, 135 "CauseMetadata": { 136 "Resource": "arn:aws:s3:::examplebucket", 137 "Provider": "aws", 138 "Service": "s3", 139 "Code": { 140 "Lines": null 141 } 142 } 143 }, 144 { 145 "Type": "AWS", 146 "ID": "AVD-AWS-0132", 147 "AVDID": "AVD-AWS-0132", 148 "Title": "S3 encryption should use Customer Managed Keys", 149 "Description": "Encryption using AWS keys provides protection for your S3 buckets. To increase control of the encryption and manage factors like rotation use customer managed keys.", 150 "Message": "Bucket does not encrypt data with a customer managed key.", 151 "Resolution": "Enable encryption using customer managed keys", 152 "Severity": "HIGH", 153 "PrimaryURL": "https://avd.aquasec.com/misconfig/avd-aws-0132", 154 "References": [ 155 "https://avd.aquasec.com/misconfig/avd-aws-0132" 156 ], 157 "Status": "FAIL", 158 "Layer": {}, 159 "CauseMetadata": { 160 "Resource": "arn:aws:s3:::examplebucket", 161 "Provider": "aws", 162 "Service": "s3", 163 "Code": { 164 "Lines": null 165 } 166 } 167 }, 168 { 169 "Type": "AWS", 170 "ID": "AVD-AWS-0091", 171 "AVDID": "AVD-AWS-0091", 172 "Title": "S3 Access Block should Ignore Public Acl", 173 "Description": "S3 buckets should ignore public ACLs on buckets and any objects they contain. By ignoring rather than blocking, PUT calls with public ACLs will still be applied but the ACL will be ignored.", 174 "Message": "No public access block so not ignoring public acls", 175 "Resolution": "Enable ignoring the application of public ACLs in PUT calls", 176 "Severity": "HIGH", 177 "PrimaryURL": "https://avd.aquasec.com/misconfig/avd-aws-0091", 178 "References": [ 179 "https://avd.aquasec.com/misconfig/avd-aws-0091" 180 ], 181 "Status": "FAIL", 182 "Layer": {}, 183 "CauseMetadata": { 184 "Resource": "arn:aws:s3:::examplebucket", 185 "Provider": "aws", 186 "Service": "s3", 187 "Code": { 188 "Lines": null 189 } 190 } 191 }, 192 { 193 "Type": "AWS", 194 "ID": "AVD-AWS-0092", 195 "AVDID": "AVD-AWS-0092", 196 "Title": "S3 Buckets not publicly accessible through ACL.", 197 "Description": "Buckets should not have ACLs that allow public access", 198 "Resolution": "Don't use canned ACLs or switch to private acl", 199 "Severity": "HIGH", 200 "PrimaryURL": "https://avd.aquasec.com/misconfig/avd-aws-0092", 201 "References": [ 202 "https://avd.aquasec.com/misconfig/avd-aws-0092" 203 ], 204 "Status": "PASS", 205 "Layer": {}, 206 "CauseMetadata": { 207 "Resource": "arn:aws:s3:::examplebucket", 208 "Provider": "aws", 209 "Service": "s3", 210 "Code": { 211 "Lines": null 212 } 213 } 214 }, 215 { 216 "Type": "AWS", 217 "ID": "AVD-AWS-0093", 218 "AVDID": "AVD-AWS-0093", 219 "Title": "S3 Access block should restrict public bucket to limit access", 220 "Description": "S3 buckets should restrict public policies for the bucket. By enabling, the restrict_public_buckets, only the bucket owner and AWS Services can access if it has a public policy.", 221 "Message": "No public access block so not restricting public buckets", 222 "Resolution": "Limit the access to public buckets to only the owner or AWS Services (eg; CloudFront)", 223 "Severity": "HIGH", 224 "PrimaryURL": "https://avd.aquasec.com/misconfig/avd-aws-0093", 225 "References": [ 226 "https://avd.aquasec.com/misconfig/avd-aws-0093" 227 ], 228 "Status": "FAIL", 229 "Layer": {}, 230 "CauseMetadata": { 231 "Resource": "arn:aws:s3:::examplebucket", 232 "Provider": "aws", 233 "Service": "s3", 234 "Code": { 235 "Lines": null 236 } 237 } 238 }, 239 { 240 "Type": "AWS", 241 "ID": "AVD-AWS-0094", 242 "AVDID": "AVD-AWS-0094", 243 "Title": "S3 buckets should each define an aws_s3_bucket_public_access_block", 244 "Description": "The \"block public access\" settings in S3 override individual policies that apply to a given bucket, meaning that all public access can be controlled in one central types for that bucket. It is therefore good practice to define these settings for each bucket in order to clearly define the public access that can be allowed for it.", 245 "Message": "Bucket does not have a corresponding public access block.", 246 "Resolution": "Define a aws_s3_bucket_public_access_block for the given bucket to control public access policies", 247 "Severity": "LOW", 248 "PrimaryURL": "https://avd.aquasec.com/misconfig/avd-aws-0094", 249 "References": [ 250 "https://avd.aquasec.com/misconfig/avd-aws-0094" 251 ], 252 "Status": "FAIL", 253 "Layer": {}, 254 "CauseMetadata": { 255 "Resource": "arn:aws:s3:::examplebucket", 256 "Provider": "aws", 257 "Service": "s3", 258 "Code": { 259 "Lines": null 260 } 261 } 262 } 263 ] 264 } 265 ] 266 } 267 ` 268 269 const expectedCustomScanResult = `{ 270 "CreatedAt": "2021-08-25T12:20:30.000000005Z", 271 "ArtifactName": "12345678", 272 "ArtifactType": "aws_account", 273 "Metadata": { 274 "ImageConfig": { 275 "architecture": "", 276 "created": "0001-01-01T00:00:00Z", 277 "os": "", 278 "rootfs": { 279 "type": "", 280 "diff_ids": null 281 }, 282 "config": {} 283 } 284 }, 285 "Results": [ 286 { 287 "Target": "", 288 "Class": "config", 289 "Type": "cloud", 290 "MisconfSummary": { 291 "Successes": 0, 292 "Failures": 1, 293 "Exceptions": 0 294 }, 295 "Misconfigurations": [ 296 { 297 "Type": "AWS", 298 "Title": "Bad input data", 299 "Description": "Just failing rule with input data", 300 "Message": "Rego policy resulted in DENY", 301 "Namespace": "user.whatever", 302 "Query": "deny", 303 "Severity": "LOW", 304 "References": [ 305 "" 306 ], 307 "Status": "FAIL", 308 "Layer": {}, 309 "CauseMetadata": { 310 "Provider": "cloud", 311 "Service": "s3", 312 "Code": { 313 "Lines": null 314 } 315 } 316 } 317 ] 318 }, 319 { 320 "Target": "arn:aws:s3:::examplebucket", 321 "Class": "config", 322 "Type": "cloud", 323 "MisconfSummary": { 324 "Successes": 1, 325 "Failures": 8, 326 "Exceptions": 0 327 }, 328 "Misconfigurations": [ 329 { 330 "Type": "AWS", 331 "ID": "AVD-AWS-0086", 332 "AVDID": "AVD-AWS-0086", 333 "Title": "S3 Access block should block public ACL", 334 "Description": "S3 buckets should block public ACLs on buckets and any objects they contain. By blocking, PUTs with fail if the object has any public ACL a.", 335 "Message": "No public access block so not blocking public acls", 336 "Resolution": "Enable blocking any PUT calls with a public ACL specified", 337 "Severity": "HIGH", 338 "PrimaryURL": "https://avd.aquasec.com/misconfig/avd-aws-0086", 339 "References": [ 340 "https://avd.aquasec.com/misconfig/avd-aws-0086" 341 ], 342 "Status": "FAIL", 343 "Layer": {}, 344 "CauseMetadata": { 345 "Resource": "arn:aws:s3:::examplebucket", 346 "Provider": "aws", 347 "Service": "s3", 348 "Code": { 349 "Lines": null 350 } 351 } 352 }, 353 { 354 "Type": "AWS", 355 "ID": "AVD-AWS-0087", 356 "AVDID": "AVD-AWS-0087", 357 "Title": "S3 Access block should block public policy", 358 "Description": "S3 bucket policy should have block public policy to prevent users from putting a policy that enable public access.", 359 "Message": "No public access block so not blocking public policies", 360 "Resolution": "Prevent policies that allow public access being PUT", 361 "Severity": "HIGH", 362 "PrimaryURL": "https://avd.aquasec.com/misconfig/avd-aws-0087", 363 "References": [ 364 "https://avd.aquasec.com/misconfig/avd-aws-0087" 365 ], 366 "Status": "FAIL", 367 "Layer": {}, 368 "CauseMetadata": { 369 "Resource": "arn:aws:s3:::examplebucket", 370 "Provider": "aws", 371 "Service": "s3", 372 "Code": { 373 "Lines": null 374 } 375 } 376 }, 377 { 378 "Type": "AWS", 379 "ID": "AVD-AWS-0088", 380 "AVDID": "AVD-AWS-0088", 381 "Title": "Unencrypted S3 bucket.", 382 "Description": "S3 Buckets should be encrypted to protect the data that is stored within them if access is compromised.", 383 "Message": "Bucket does not have encryption enabled", 384 "Resolution": "Configure bucket encryption", 385 "Severity": "HIGH", 386 "PrimaryURL": "https://avd.aquasec.com/misconfig/avd-aws-0088", 387 "References": [ 388 "https://avd.aquasec.com/misconfig/avd-aws-0088" 389 ], 390 "Status": "FAIL", 391 "Layer": {}, 392 "CauseMetadata": { 393 "Resource": "arn:aws:s3:::examplebucket", 394 "Provider": "aws", 395 "Service": "s3", 396 "Code": { 397 "Lines": null 398 } 399 } 400 }, 401 { 402 "Type": "AWS", 403 "ID": "AVD-AWS-0090", 404 "AVDID": "AVD-AWS-0090", 405 "Title": "S3 Data should be versioned", 406 "Description": "Versioning in Amazon S3 is a means of keeping multiple variants of an object in the same bucket. \nYou can use the S3 Versioning feature to preserve, retrieve, and restore every version of every object stored in your buckets. \nWith versioning you can recover more easily from both unintended user actions and application failures.", 407 "Message": "Bucket does not have versioning enabled", 408 "Resolution": "Enable versioning to protect against accidental/malicious removal or modification", 409 "Severity": "MEDIUM", 410 "PrimaryURL": "https://avd.aquasec.com/misconfig/avd-aws-0090", 411 "References": [ 412 "https://avd.aquasec.com/misconfig/avd-aws-0090" 413 ], 414 "Status": "FAIL", 415 "Layer": {}, 416 "CauseMetadata": { 417 "Resource": "arn:aws:s3:::examplebucket", 418 "Provider": "aws", 419 "Service": "s3", 420 "Code": { 421 "Lines": null 422 } 423 } 424 }, 425 { 426 "Type": "AWS", 427 "ID": "AVD-AWS-0132", 428 "AVDID": "AVD-AWS-0132", 429 "Title": "S3 encryption should use Customer Managed Keys", 430 "Description": "Encryption using AWS keys provides protection for your S3 buckets. To increase control of the encryption and manage factors like rotation use customer managed keys.", 431 "Message": "Bucket does not encrypt data with a customer managed key.", 432 "Resolution": "Enable encryption using customer managed keys", 433 "Severity": "HIGH", 434 "PrimaryURL": "https://avd.aquasec.com/misconfig/avd-aws-0132", 435 "References": [ 436 "https://avd.aquasec.com/misconfig/avd-aws-0132" 437 ], 438 "Status": "FAIL", 439 "Layer": {}, 440 "CauseMetadata": { 441 "Resource": "arn:aws:s3:::examplebucket", 442 "Provider": "aws", 443 "Service": "s3", 444 "Code": { 445 "Lines": null 446 } 447 } 448 }, 449 { 450 "Type": "AWS", 451 "ID": "AVD-AWS-0091", 452 "AVDID": "AVD-AWS-0091", 453 "Title": "S3 Access Block should Ignore Public Acl", 454 "Description": "S3 buckets should ignore public ACLs on buckets and any objects they contain. By ignoring rather than blocking, PUT calls with public ACLs will still be applied but the ACL will be ignored.", 455 "Message": "No public access block so not ignoring public acls", 456 "Resolution": "Enable ignoring the application of public ACLs in PUT calls", 457 "Severity": "HIGH", 458 "PrimaryURL": "https://avd.aquasec.com/misconfig/avd-aws-0091", 459 "References": [ 460 "https://avd.aquasec.com/misconfig/avd-aws-0091" 461 ], 462 "Status": "FAIL", 463 "Layer": {}, 464 "CauseMetadata": { 465 "Resource": "arn:aws:s3:::examplebucket", 466 "Provider": "aws", 467 "Service": "s3", 468 "Code": { 469 "Lines": null 470 } 471 } 472 }, 473 { 474 "Type": "AWS", 475 "ID": "AVD-AWS-0092", 476 "AVDID": "AVD-AWS-0092", 477 "Title": "S3 Buckets not publicly accessible through ACL.", 478 "Description": "Buckets should not have ACLs that allow public access", 479 "Resolution": "Don't use canned ACLs or switch to private acl", 480 "Severity": "HIGH", 481 "PrimaryURL": "https://avd.aquasec.com/misconfig/avd-aws-0092", 482 "References": [ 483 "https://avd.aquasec.com/misconfig/avd-aws-0092" 484 ], 485 "Status": "PASS", 486 "Layer": {}, 487 "CauseMetadata": { 488 "Resource": "arn:aws:s3:::examplebucket", 489 "Provider": "aws", 490 "Service": "s3", 491 "Code": { 492 "Lines": null 493 } 494 } 495 }, 496 { 497 "Type": "AWS", 498 "ID": "AVD-AWS-0093", 499 "AVDID": "AVD-AWS-0093", 500 "Title": "S3 Access block should restrict public bucket to limit access", 501 "Description": "S3 buckets should restrict public policies for the bucket. By enabling, the restrict_public_buckets, only the bucket owner and AWS Services can access if it has a public policy.", 502 "Message": "No public access block so not restricting public buckets", 503 "Resolution": "Limit the access to public buckets to only the owner or AWS Services (eg; CloudFront)", 504 "Severity": "HIGH", 505 "PrimaryURL": "https://avd.aquasec.com/misconfig/avd-aws-0093", 506 "References": [ 507 "https://avd.aquasec.com/misconfig/avd-aws-0093" 508 ], 509 "Status": "FAIL", 510 "Layer": {}, 511 "CauseMetadata": { 512 "Resource": "arn:aws:s3:::examplebucket", 513 "Provider": "aws", 514 "Service": "s3", 515 "Code": { 516 "Lines": null 517 } 518 } 519 }, 520 { 521 "Type": "AWS", 522 "ID": "AVD-AWS-0094", 523 "AVDID": "AVD-AWS-0094", 524 "Title": "S3 buckets should each define an aws_s3_bucket_public_access_block", 525 "Description": "The \"block public access\" settings in S3 override individual policies that apply to a given bucket, meaning that all public access can be controlled in one central types for that bucket. It is therefore good practice to define these settings for each bucket in order to clearly define the public access that can be allowed for it.", 526 "Message": "Bucket does not have a corresponding public access block.", 527 "Resolution": "Define a aws_s3_bucket_public_access_block for the given bucket to control public access policies", 528 "Severity": "LOW", 529 "PrimaryURL": "https://avd.aquasec.com/misconfig/avd-aws-0094", 530 "References": [ 531 "https://avd.aquasec.com/misconfig/avd-aws-0094" 532 ], 533 "Status": "FAIL", 534 "Layer": {}, 535 "CauseMetadata": { 536 "Resource": "arn:aws:s3:::examplebucket", 537 "Provider": "aws", 538 "Service": "s3", 539 "Code": { 540 "Lines": null 541 } 542 } 543 } 544 ] 545 } 546 ] 547 } 548 ` 549 550 const expectedS3AndCloudTrailResult = `{ 551 "CreatedAt": "2021-08-25T12:20:30.000000005Z", 552 "ArtifactName": "123456789", 553 "ArtifactType": "aws_account", 554 "Metadata": { 555 "ImageConfig": { 556 "architecture": "", 557 "created": "0001-01-01T00:00:00Z", 558 "os": "", 559 "rootfs": { 560 "type": "", 561 "diff_ids": null 562 }, 563 "config": {} 564 } 565 }, 566 "Results": [ 567 { 568 "Target": "arn:aws:cloudtrail:us-east-1:12345678:trail/management-events", 569 "Class": "config", 570 "Type": "cloud", 571 "MisconfSummary": { 572 "Successes": 1, 573 "Failures": 3, 574 "Exceptions": 0 575 }, 576 "Misconfigurations": [ 577 { 578 "Type": "AWS", 579 "ID": "AVD-AWS-0014", 580 "AVDID": "AVD-AWS-0014", 581 "Title": "Cloudtrail should be enabled in all regions regardless of where your AWS resources are generally homed", 582 "Description": "When creating Cloudtrail in the AWS Management Console the trail is configured by default to be multi-region, this isn't the case with the Terraform resource. Cloudtrail should cover the full AWS account to ensure you can track changes in regions you are not actively operting in.", 583 "Resolution": "Enable Cloudtrail in all regions", 584 "Severity": "MEDIUM", 585 "PrimaryURL": "https://avd.aquasec.com/misconfig/avd-aws-0014", 586 "References": [ 587 "https://avd.aquasec.com/misconfig/avd-aws-0014" 588 ], 589 "Status": "PASS", 590 "Layer": {}, 591 "CauseMetadata": { 592 "Resource": "arn:aws:cloudtrail:us-east-1:12345678:trail/management-events", 593 "Provider": "aws", 594 "Service": "cloudtrail", 595 "Code": { 596 "Lines": null 597 } 598 } 599 }, 600 { 601 "Type": "AWS", 602 "ID": "AVD-AWS-0015", 603 "AVDID": "AVD-AWS-0015", 604 "Title": "Cloudtrail should be encrypted at rest to secure access to sensitive trail data", 605 "Description": "Cloudtrail logs should be encrypted at rest to secure the sensitive data. Cloudtrail logs record all activity that occurs in the the account through API calls and would be one of the first places to look when reacting to a breach.", 606 "Message": "Trail is not encrypted.", 607 "Resolution": "Enable encryption at rest", 608 "Severity": "HIGH", 609 "PrimaryURL": "https://avd.aquasec.com/misconfig/avd-aws-0015", 610 "References": [ 611 "https://avd.aquasec.com/misconfig/avd-aws-0015" 612 ], 613 "Status": "FAIL", 614 "Layer": {}, 615 "CauseMetadata": { 616 "Resource": "arn:aws:cloudtrail:us-east-1:12345678:trail/management-events", 617 "Provider": "aws", 618 "Service": "cloudtrail", 619 "Code": { 620 "Lines": null 621 } 622 } 623 }, 624 { 625 "Type": "AWS", 626 "ID": "AVD-AWS-0016", 627 "AVDID": "AVD-AWS-0016", 628 "Title": "Cloudtrail log validation should be enabled to prevent tampering of log data", 629 "Description": "Log validation should be activated on Cloudtrail logs to prevent the tampering of the underlying data in the S3 bucket. It is feasible that a rogue actor compromising an AWS account might want to modify the log data to remove trace of their actions.", 630 "Message": "Trail does not have log validation enabled.", 631 "Resolution": "Turn on log validation for Cloudtrail", 632 "Severity": "HIGH", 633 "PrimaryURL": "https://avd.aquasec.com/misconfig/avd-aws-0016", 634 "References": [ 635 "https://avd.aquasec.com/misconfig/avd-aws-0016" 636 ], 637 "Status": "FAIL", 638 "Layer": {}, 639 "CauseMetadata": { 640 "Resource": "arn:aws:cloudtrail:us-east-1:12345678:trail/management-events", 641 "Provider": "aws", 642 "Service": "cloudtrail", 643 "Code": { 644 "Lines": null 645 } 646 } 647 }, 648 { 649 "Type": "AWS", 650 "ID": "AVD-AWS-0162", 651 "AVDID": "AVD-AWS-0162", 652 "Title": "CloudTrail logs should be stored in S3 and also sent to CloudWatch Logs", 653 "Description": "CloudTrail is a web service that records AWS API calls made in a given account. The recorded information includes the identity of the API caller, the time of the API call, the source IP address of the API caller, the request parameters, and the response elements returned by the AWS service.\n\nCloudTrail uses Amazon S3 for log file storage and delivery, so log files are stored durably. In addition to capturing CloudTrail logs in a specified Amazon S3 bucket for long-term analysis, you can perform real-time analysis by configuring CloudTrail to send logs to CloudWatch Logs.\n\nFor a trail that is enabled in all Regions in an account, CloudTrail sends log files from all those Regions to a CloudWatch Logs log group.", 654 "Message": "Trail does not have CloudWatch logging configured", 655 "Resolution": "Enable logging to CloudWatch", 656 "Severity": "LOW", 657 "PrimaryURL": "https://avd.aquasec.com/misconfig/avd-aws-0162", 658 "References": [ 659 "https://avd.aquasec.com/misconfig/avd-aws-0162" 660 ], 661 "Status": "FAIL", 662 "Layer": {}, 663 "CauseMetadata": { 664 "Resource": "arn:aws:cloudtrail:us-east-1:12345678:trail/management-events", 665 "Provider": "aws", 666 "Service": "cloudtrail", 667 "Code": { 668 "Lines": null 669 } 670 } 671 } 672 ] 673 }, 674 { 675 "Target": "arn:aws:s3:::examplebucket", 676 "Class": "config", 677 "Type": "cloud", 678 "MisconfSummary": { 679 "Successes": 1, 680 "Failures": 8, 681 "Exceptions": 0 682 }, 683 "Misconfigurations": [ 684 { 685 "Type": "AWS", 686 "ID": "AVD-AWS-0086", 687 "AVDID": "AVD-AWS-0086", 688 "Title": "S3 Access block should block public ACL", 689 "Description": "S3 buckets should block public ACLs on buckets and any objects they contain. By blocking, PUTs with fail if the object has any public ACL a.", 690 "Message": "No public access block so not blocking public acls", 691 "Resolution": "Enable blocking any PUT calls with a public ACL specified", 692 "Severity": "HIGH", 693 "PrimaryURL": "https://avd.aquasec.com/misconfig/avd-aws-0086", 694 "References": [ 695 "https://avd.aquasec.com/misconfig/avd-aws-0086" 696 ], 697 "Status": "FAIL", 698 "Layer": {}, 699 "CauseMetadata": { 700 "Resource": "arn:aws:s3:::examplebucket", 701 "Provider": "aws", 702 "Service": "s3", 703 "Code": { 704 "Lines": null 705 } 706 } 707 }, 708 { 709 "Type": "AWS", 710 "ID": "AVD-AWS-0087", 711 "AVDID": "AVD-AWS-0087", 712 "Title": "S3 Access block should block public policy", 713 "Description": "S3 bucket policy should have block public policy to prevent users from putting a policy that enable public access.", 714 "Message": "No public access block so not blocking public policies", 715 "Resolution": "Prevent policies that allow public access being PUT", 716 "Severity": "HIGH", 717 "PrimaryURL": "https://avd.aquasec.com/misconfig/avd-aws-0087", 718 "References": [ 719 "https://avd.aquasec.com/misconfig/avd-aws-0087" 720 ], 721 "Status": "FAIL", 722 "Layer": {}, 723 "CauseMetadata": { 724 "Resource": "arn:aws:s3:::examplebucket", 725 "Provider": "aws", 726 "Service": "s3", 727 "Code": { 728 "Lines": null 729 } 730 } 731 }, 732 { 733 "Type": "AWS", 734 "ID": "AVD-AWS-0088", 735 "AVDID": "AVD-AWS-0088", 736 "Title": "Unencrypted S3 bucket.", 737 "Description": "S3 Buckets should be encrypted to protect the data that is stored within them if access is compromised.", 738 "Message": "Bucket does not have encryption enabled", 739 "Resolution": "Configure bucket encryption", 740 "Severity": "HIGH", 741 "PrimaryURL": "https://avd.aquasec.com/misconfig/avd-aws-0088", 742 "References": [ 743 "https://avd.aquasec.com/misconfig/avd-aws-0088" 744 ], 745 "Status": "FAIL", 746 "Layer": {}, 747 "CauseMetadata": { 748 "Resource": "arn:aws:s3:::examplebucket", 749 "Provider": "aws", 750 "Service": "s3", 751 "Code": { 752 "Lines": null 753 } 754 } 755 }, 756 { 757 "Type": "AWS", 758 "ID": "AVD-AWS-0090", 759 "AVDID": "AVD-AWS-0090", 760 "Title": "S3 Data should be versioned", 761 "Description": "Versioning in Amazon S3 is a means of keeping multiple variants of an object in the same bucket. \nYou can use the S3 Versioning feature to preserve, retrieve, and restore every version of every object stored in your buckets. \nWith versioning you can recover more easily from both unintended user actions and application failures.", 762 "Message": "Bucket does not have versioning enabled", 763 "Resolution": "Enable versioning to protect against accidental/malicious removal or modification", 764 "Severity": "MEDIUM", 765 "PrimaryURL": "https://avd.aquasec.com/misconfig/avd-aws-0090", 766 "References": [ 767 "https://avd.aquasec.com/misconfig/avd-aws-0090" 768 ], 769 "Status": "FAIL", 770 "Layer": {}, 771 "CauseMetadata": { 772 "Resource": "arn:aws:s3:::examplebucket", 773 "Provider": "aws", 774 "Service": "s3", 775 "Code": { 776 "Lines": null 777 } 778 } 779 }, 780 { 781 "Type": "AWS", 782 "ID": "AVD-AWS-0132", 783 "AVDID": "AVD-AWS-0132", 784 "Title": "S3 encryption should use Customer Managed Keys", 785 "Description": "Encryption using AWS keys provides protection for your S3 buckets. To increase control of the encryption and manage factors like rotation use customer managed keys.", 786 "Message": "Bucket does not encrypt data with a customer managed key.", 787 "Resolution": "Enable encryption using customer managed keys", 788 "Severity": "HIGH", 789 "PrimaryURL": "https://avd.aquasec.com/misconfig/avd-aws-0132", 790 "References": [ 791 "https://avd.aquasec.com/misconfig/avd-aws-0132" 792 ], 793 "Status": "FAIL", 794 "Layer": {}, 795 "CauseMetadata": { 796 "Resource": "arn:aws:s3:::examplebucket", 797 "Provider": "aws", 798 "Service": "s3", 799 "Code": { 800 "Lines": null 801 } 802 } 803 }, 804 { 805 "Type": "AWS", 806 "ID": "AVD-AWS-0091", 807 "AVDID": "AVD-AWS-0091", 808 "Title": "S3 Access Block should Ignore Public Acl", 809 "Description": "S3 buckets should ignore public ACLs on buckets and any objects they contain. By ignoring rather than blocking, PUT calls with public ACLs will still be applied but the ACL will be ignored.", 810 "Message": "No public access block so not ignoring public acls", 811 "Resolution": "Enable ignoring the application of public ACLs in PUT calls", 812 "Severity": "HIGH", 813 "PrimaryURL": "https://avd.aquasec.com/misconfig/avd-aws-0091", 814 "References": [ 815 "https://avd.aquasec.com/misconfig/avd-aws-0091" 816 ], 817 "Status": "FAIL", 818 "Layer": {}, 819 "CauseMetadata": { 820 "Resource": "arn:aws:s3:::examplebucket", 821 "Provider": "aws", 822 "Service": "s3", 823 "Code": { 824 "Lines": null 825 } 826 } 827 }, 828 { 829 "Type": "AWS", 830 "ID": "AVD-AWS-0092", 831 "AVDID": "AVD-AWS-0092", 832 "Title": "S3 Buckets not publicly accessible through ACL.", 833 "Description": "Buckets should not have ACLs that allow public access", 834 "Resolution": "Don't use canned ACLs or switch to private acl", 835 "Severity": "HIGH", 836 "PrimaryURL": "https://avd.aquasec.com/misconfig/avd-aws-0092", 837 "References": [ 838 "https://avd.aquasec.com/misconfig/avd-aws-0092" 839 ], 840 "Status": "PASS", 841 "Layer": {}, 842 "CauseMetadata": { 843 "Resource": "arn:aws:s3:::examplebucket", 844 "Provider": "aws", 845 "Service": "s3", 846 "Code": { 847 "Lines": null 848 } 849 } 850 }, 851 { 852 "Type": "AWS", 853 "ID": "AVD-AWS-0093", 854 "AVDID": "AVD-AWS-0093", 855 "Title": "S3 Access block should restrict public bucket to limit access", 856 "Description": "S3 buckets should restrict public policies for the bucket. By enabling, the restrict_public_buckets, only the bucket owner and AWS Services can access if it has a public policy.", 857 "Message": "No public access block so not restricting public buckets", 858 "Resolution": "Limit the access to public buckets to only the owner or AWS Services (eg; CloudFront)", 859 "Severity": "HIGH", 860 "PrimaryURL": "https://avd.aquasec.com/misconfig/avd-aws-0093", 861 "References": [ 862 "https://avd.aquasec.com/misconfig/avd-aws-0093" 863 ], 864 "Status": "FAIL", 865 "Layer": {}, 866 "CauseMetadata": { 867 "Resource": "arn:aws:s3:::examplebucket", 868 "Provider": "aws", 869 "Service": "s3", 870 "Code": { 871 "Lines": null 872 } 873 } 874 }, 875 { 876 "Type": "AWS", 877 "ID": "AVD-AWS-0094", 878 "AVDID": "AVD-AWS-0094", 879 "Title": "S3 buckets should each define an aws_s3_bucket_public_access_block", 880 "Description": "The \"block public access\" settings in S3 override individual policies that apply to a given bucket, meaning that all public access can be controlled in one central types for that bucket. It is therefore good practice to define these settings for each bucket in order to clearly define the public access that can be allowed for it.", 881 "Message": "Bucket does not have a corresponding public access block.", 882 "Resolution": "Define a aws_s3_bucket_public_access_block for the given bucket to control public access policies", 883 "Severity": "LOW", 884 "PrimaryURL": "https://avd.aquasec.com/misconfig/avd-aws-0094", 885 "References": [ 886 "https://avd.aquasec.com/misconfig/avd-aws-0094" 887 ], 888 "Status": "FAIL", 889 "Layer": {}, 890 "CauseMetadata": { 891 "Resource": "arn:aws:s3:::examplebucket", 892 "Provider": "aws", 893 "Service": "s3", 894 "Code": { 895 "Lines": null 896 } 897 } 898 } 899 ] 900 } 901 ] 902 } 903 ` 904 905 func Test_Run(t *testing.T) { 906 regoDir := t.TempDir() 907 908 tests := []struct { 909 name string 910 options flag.Options 911 want string 912 expectErr bool 913 cacheContent string 914 regoPolicy string 915 allServices []string 916 inputData string 917 }{ 918 { 919 name: "succeed with cached infra", 920 options: flag.Options{ 921 RegoOptions: flag.RegoOptions{SkipPolicyUpdate: true}, 922 AWSOptions: flag.AWSOptions{ 923 Region: "us-east-1", 924 Services: []string{"s3"}, 925 Account: "12345678", 926 }, 927 CloudOptions: flag.CloudOptions{ 928 MaxCacheAge: time.Hour * 24 * 365 * 100, 929 }, 930 MisconfOptions: flag.MisconfOptions{IncludeNonFailures: true}, 931 }, 932 cacheContent: "testdata/s3onlycache.json", 933 allServices: []string{"s3"}, 934 want: expectedS3ScanResult, 935 }, 936 { 937 name: "custom rego rule with passed results", 938 options: flag.Options{ 939 AWSOptions: flag.AWSOptions{ 940 Region: "us-east-1", 941 Services: []string{"s3"}, 942 Account: "12345678", 943 }, 944 CloudOptions: flag.CloudOptions{ 945 MaxCacheAge: time.Hour * 24 * 365 * 100, 946 }, 947 RegoOptions: flag.RegoOptions{ 948 Trace: true, 949 PolicyPaths: []string{ 950 filepath.Join(regoDir, "policies"), 951 }, 952 PolicyNamespaces: []string{ 953 "user", 954 }, 955 DataPaths: []string{ 956 filepath.Join(regoDir, "data"), 957 }, 958 SkipPolicyUpdate: true, 959 }, 960 MisconfOptions: flag.MisconfOptions{IncludeNonFailures: true}, 961 }, 962 regoPolicy: `# METADATA 963 # title: Bad input data 964 # description: Just failing rule with input data 965 # scope: package 966 # schemas: 967 # - input: schema["input"] 968 # custom: 969 # severity: LOW 970 # service: s3 971 # input: 972 # selector: 973 # - type: cloud 974 package user.whatever 975 import data.settings.DS123.foo 976 977 deny { 978 foo == true 979 } 980 `, 981 inputData: `{ 982 "settings": { 983 "DS123": { 984 "foo": true 985 } 986 } 987 }`, 988 cacheContent: filepath.Join("testdata", "s3onlycache.json"), 989 allServices: []string{"s3"}, 990 want: expectedCustomScanResult, 991 }, 992 { 993 name: "compliance report summary", 994 options: flag.Options{ 995 AWSOptions: flag.AWSOptions{ 996 Region: "us-east-1", 997 Services: []string{"s3"}, 998 Account: "12345678", 999 }, 1000 CloudOptions: flag.CloudOptions{ 1001 MaxCacheAge: time.Hour * 24 * 365 * 100, 1002 }, 1003 ReportOptions: flag.ReportOptions{ 1004 Compliance: spec.ComplianceSpec{ 1005 Spec: defsecTypes.Spec{ 1006 // TODO: refactor defsec so that the parsed spec can be passed 1007 ID: "@testdata/example-spec.yaml", 1008 Title: "my-custom-spec", 1009 Description: "My fancy spec", 1010 Version: "1.2", 1011 Controls: []defsecTypes.Control{ 1012 { 1013 ID: "1.1", 1014 Name: "Unencrypted S3 bucket", 1015 Description: "S3 Buckets should be encrypted to protect the data that is stored within them if access is compromised.", 1016 Checks: []defsecTypes.SpecCheck{ 1017 {ID: "AVD-AWS-0088"}, 1018 }, 1019 Severity: "HIGH", 1020 }, 1021 }, 1022 }, 1023 }, 1024 Format: "table", 1025 ReportFormat: "summary", 1026 }, 1027 RegoOptions: flag.RegoOptions{SkipPolicyUpdate: true}, 1028 }, 1029 cacheContent: "testdata/s3onlycache.json", 1030 allServices: []string{"s3"}, 1031 want: ` 1032 Summary Report for compliance: my-custom-spec 1033 ┌─────┬──────────┬───────────────────────┬────────┬────────┐ 1034 │ ID │ Severity │ Control Name │ Status │ Issues │ 1035 ├─────┼──────────┼───────────────────────┼────────┼────────┤ 1036 │ 1.1 │ HIGH │ Unencrypted S3 bucket │ FAIL │ 1 │ 1037 └─────┴──────────┴───────────────────────┴────────┴────────┘ 1038 `, 1039 }, 1040 { 1041 name: "scan an unsupported service", 1042 options: flag.Options{ 1043 RegoOptions: flag.RegoOptions{SkipPolicyUpdate: true}, 1044 AWSOptions: flag.AWSOptions{ 1045 Region: "us-east-1", 1046 Account: "123456789", 1047 Services: []string{"theultimateservice"}, 1048 }, 1049 CloudOptions: flag.CloudOptions{ 1050 MaxCacheAge: time.Hour * 24 * 365 * 100, 1051 }, 1052 MisconfOptions: flag.MisconfOptions{IncludeNonFailures: true}, 1053 }, 1054 cacheContent: "testdata/s3onlycache.json", 1055 expectErr: true, 1056 }, 1057 { 1058 name: "scan every service", 1059 options: flag.Options{ 1060 RegoOptions: flag.RegoOptions{SkipPolicyUpdate: true}, 1061 AWSOptions: flag.AWSOptions{ 1062 Region: "us-east-1", 1063 Account: "123456789", 1064 }, 1065 CloudOptions: flag.CloudOptions{ 1066 MaxCacheAge: time.Hour * 24 * 365 * 100, 1067 }, 1068 MisconfOptions: flag.MisconfOptions{IncludeNonFailures: true}, 1069 }, 1070 cacheContent: "testdata/s3andcloudtrailcache.json", 1071 allServices: []string{"s3", "cloudtrail"}, 1072 want: expectedS3AndCloudTrailResult, 1073 }, 1074 { 1075 name: "skip certain services and include specific services", 1076 options: flag.Options{ 1077 RegoOptions: flag.RegoOptions{SkipPolicyUpdate: true}, 1078 AWSOptions: flag.AWSOptions{ 1079 Region: "us-east-1", 1080 Services: []string{"s3"}, 1081 SkipServices: []string{"cloudtrail"}, 1082 Account: "123456789", 1083 }, 1084 CloudOptions: flag.CloudOptions{ 1085 MaxCacheAge: time.Hour * 24 * 365 * 100, 1086 }, 1087 MisconfOptions: flag.MisconfOptions{IncludeNonFailures: true}, 1088 }, 1089 cacheContent: "testdata/s3andcloudtrailcache.json", 1090 allServices: []string{"s3", "cloudtrail"}, 1091 // we skip cloudtrail but still expect results from it as it is cached 1092 want: expectedS3AndCloudTrailResult, 1093 }, 1094 { 1095 name: "only skip certain services but scan the rest", 1096 options: flag.Options{ 1097 RegoOptions: flag.RegoOptions{SkipPolicyUpdate: true}, 1098 AWSOptions: flag.AWSOptions{ 1099 Region: "us-east-1", 1100 SkipServices: []string{"cloudtrail", "iam"}, 1101 Account: "12345678", 1102 }, 1103 CloudOptions: flag.CloudOptions{ 1104 MaxCacheAge: time.Hour * 24 * 365 * 100, 1105 }, 1106 MisconfOptions: flag.MisconfOptions{IncludeNonFailures: true}, 1107 }, 1108 allServices: []string{"s3", "cloudtrail", "iam"}, 1109 cacheContent: "testdata/s3onlycache.json", 1110 want: expectedS3ScanResult, 1111 }, 1112 { 1113 name: "fail - service specified to both include and exclude", 1114 options: flag.Options{ 1115 RegoOptions: flag.RegoOptions{SkipPolicyUpdate: true}, 1116 AWSOptions: flag.AWSOptions{ 1117 Region: "us-east-1", 1118 Services: []string{"s3"}, 1119 SkipServices: []string{"s3"}, 1120 Account: "123456789", 1121 }, 1122 CloudOptions: flag.CloudOptions{ 1123 MaxCacheAge: time.Hour * 24 * 365 * 100, 1124 }, 1125 MisconfOptions: flag.MisconfOptions{IncludeNonFailures: true}, 1126 }, 1127 cacheContent: "testdata/s3andcloudtrailcache.json", 1128 expectErr: true, 1129 }, 1130 } 1131 1132 clock.SetFakeTime(t, time.Date(2021, 8, 25, 12, 20, 30, 5, time.UTC)) 1133 for _, test := range tests { 1134 t.Run(test.name, func(t *testing.T) { 1135 if test.allServices != nil { 1136 oldAllSupportedServicesFunc := allSupportedServicesFunc 1137 allSupportedServicesFunc = func() []string { 1138 return test.allServices 1139 } 1140 defer func() { 1141 allSupportedServicesFunc = oldAllSupportedServicesFunc 1142 }() 1143 } 1144 1145 output := bytes.NewBuffer(nil) 1146 test.options.SetOutputWriter(output) 1147 test.options.Debug = true 1148 test.options.GlobalOptions.Timeout = time.Minute 1149 if test.options.Format == "" { 1150 test.options.Format = "json" 1151 } 1152 test.options.Severities = []dbTypes.Severity{ 1153 dbTypes.SeverityUnknown, 1154 dbTypes.SeverityLow, 1155 dbTypes.SeverityMedium, 1156 dbTypes.SeverityHigh, 1157 dbTypes.SeverityCritical, 1158 } 1159 1160 if test.regoPolicy != "" { 1161 require.NoError(t, os.MkdirAll(filepath.Join(regoDir, "policies"), 0755)) 1162 require.NoError(t, os.WriteFile(filepath.Join(regoDir, "policies", "user.rego"), []byte(test.regoPolicy), 0644)) 1163 } 1164 1165 if test.inputData != "" { 1166 require.NoError(t, os.MkdirAll(filepath.Join(regoDir, "data"), 0755)) 1167 require.NoError(t, os.WriteFile(filepath.Join(regoDir, "data", "data.json"), []byte(test.inputData), 0644)) 1168 } 1169 1170 if test.cacheContent != "" { 1171 cacheRoot := t.TempDir() 1172 test.options.CacheDir = cacheRoot 1173 cacheFile := filepath.Join(cacheRoot, "cloud", "aws", test.options.Account, test.options.Region, "data.json") 1174 require.NoError(t, os.MkdirAll(filepath.Dir(cacheFile), 0700)) 1175 1176 cacheData, err := os.ReadFile(test.cacheContent) 1177 require.NoError(t, err, test.name) 1178 1179 require.NoError(t, os.WriteFile(cacheFile, cacheData, 0600)) 1180 } 1181 1182 err := Run(context.Background(), test.options) 1183 if test.expectErr { 1184 assert.Error(t, err) 1185 return 1186 } 1187 assert.NoError(t, err) 1188 assert.Equal(t, test.want, output.String()) 1189 }) 1190 } 1191 }