├── .prismaCloud └── config.yml ├── CFT ├── cft_aws_json_all_issues.json ├── cft_aws_json_fixed_issues.json ├── cft_aws_json_with_issues.json ├── cft_aws_json_with_issues_variable_files.json ├── cft_aws_json_with_issues_variable_values.json └── cft_variables.json ├── K8S ├── k8s_fixed_issues.yml └── k8s_with_issues.yml ├── LICENSE ├── Postman Collection ├── README.md ├── api_server_environment.postman_collection.json ├── cft_demo.postman_collection.json ├── k8s_demo.postman_collection.json ├── tf12_demo.postman_collection.json └── tfplan_demo.postman_collection.json ├── README.md ├── TF ├── tf12_aws_all_issues │ └── tf12_aws_all_issues.tf ├── tf12_fixed_issues │ └── tf12_fixed_issues.tf ├── tf12_gcp_all_issues │ └── gcp_all_issues.tf ├── tf12_multiple-modules │ ├── examples │ │ ├── complete │ │ │ ├── README.md │ │ │ ├── main.tf │ │ │ └── outputs.tf │ │ └── s3-replication │ │ │ ├── README.md │ │ │ ├── iam.tf │ │ │ ├── main.tf │ │ │ └── outputs.tf │ ├── main.tf │ ├── outputs.tf │ └── variables.tf ├── tf12_nested_variable_files │ ├── main.tf │ ├── network │ │ └── smelks.tfvars │ └── variables.tf ├── tf12_rich-value-types │ ├── main.tf │ └── network │ │ ├── main.tf │ │ ├── outputs.tf │ │ ├── smvariables.tfvars │ │ └── variables.tf ├── tf12_variable_files │ ├── main.tf │ ├── smelks.tfvars │ └── variables.tf ├── tf12_variable_values │ ├── main.tf │ └── variables.tf └── tf12_with_issues │ └── tf12_with_issues.tf └── TF_Plan └── tfplan.json /.prismaCloud/config.yml: -------------------------------------------------------------------------------- 1 | # This is the configuration file for Iac Scan APIv2. 2 | 3 | # Specify the template types.The valid values are TF, CFT, K8S 4 | template_type: TF 5 | 6 | # For Terraform, it is recommended to provide one of the following values: 0.11, 0.12 or 0.13. 7 | # For CFT and K8s, this can be omitted. 8 | template_version: 0.12 9 | 10 | # For your template_type, fill in the details where applicable. 11 | # variables: Specify any environment variables(TF) or parameters(CFT) as key:value pairs under this attribute. 12 | # variable_files: Specify all the custom variable_files under here. It is an array of strings. 13 | # variable_files: If it is standard extension(.tfvars for terraform), then this can be omitted. 14 | # variable_files: For a custom extension, specify the variable file path from the root of the repo. 15 | template_parameters: 16 | variable_files: 17 | - './TF/tf12_variable_files/smelks.tfvars' 18 | - './TF/tf12_nested_variable_files/network/smelks.tfvars' 19 | variables: 20 | cidr: 0.0.0.0/0 21 | acl: public-read-write 22 | AccessControl: PublicRead 23 | 24 | # Define tags to identify your particular scan. You can use these tags to search the scan details on the Prisma Cloud. 25 | tags: 26 | Org: Engineering 27 | Team: Shift_Left 28 | Env: Dev 29 | -------------------------------------------------------------------------------- /CFT/cft_aws_json_all_issues.json: -------------------------------------------------------------------------------- 1 | { 2 | "AWSTemplateFormatVersion": "2010-09-09", 3 | "Description": "Hadoop Cluster (HDP 2.3)", 4 | "Resources": { 5 | "S3Bucket": { 6 | "Type": "AWS::S3::Bucket", 7 | "Properties": { 8 | "AccessControl": "PublicRead", 9 | "CorsConfiguration": { 10 | "CorsRules": [ 11 | { 12 | "AllowedHeaders": [ 13 | "*" 14 | ], 15 | "AllowedMethods": [ 16 | "GET" 17 | ], 18 | "AllowedOrigins": [ 19 | "*" 20 | ], 21 | "ExposedHeaders": [ 22 | "Date" 23 | ], 24 | "Id": "myCORSRuleId1", 25 | "MaxAge": "3600" 26 | }, 27 | { 28 | "AllowedHeaders": [ 29 | "x-amz-*" 30 | ], 31 | "AllowedMethods": [ 32 | "DELETE" 33 | ], 34 | "AllowedOrigins": [ 35 | "http://www.example1.com", 36 | "http://www.example2.com" 37 | ], 38 | "ExposedHeaders": [ 39 | "Connection", 40 | "Server", 41 | "Date" 42 | ], 43 | "Id": "myCORSRuleId2", 44 | "MaxAge": "1800" 45 | } 46 | ] 47 | } 48 | } 49 | }, 50 | "myTrail": { 51 | "Type": "AWS::CloudTrail::Trail", 52 | "DependsOn": [ 53 | "BucketPolicy", 54 | "TopicPolicy" 55 | ], 56 | "Properties": { 57 | "IsMultiRegionTrail": false, 58 | "S3BucketName": { 59 | "Ref": "S3Bucket" 60 | }, 61 | "SnsTopicName": { 62 | "Fn::GetAtt": [ 63 | "Topic", 64 | "TopicName" 65 | ] 66 | }, 67 | "IsLogging": true 68 | } 69 | }, 70 | "kmsKey": { 71 | "Type": "AWS::KMS::Key", 72 | "Properties": { 73 | "EnableKeyRotation": false 74 | } 75 | }, 76 | "taskdefinition": { 77 | "Type": "AWS::ECS::TaskDefinition", 78 | "Properties": { 79 | "RequiresCompatibilities": [ 80 | "EC2", 81 | "FARGATE" 82 | ], 83 | "ContainerDefinitions": [ 84 | { 85 | "Name": "my-app", 86 | "MountPoints": [ 87 | { 88 | "SourceVolume": "my-vol", 89 | "ContainerPath": "/var/www/my-vol" 90 | } 91 | ], 92 | "Image": "amazon/amazon-ecs-sample", 93 | "Cpu": "10", 94 | "EntryPoint": [ 95 | "/usr/sbin/apache2", 96 | "-D", 97 | "FOREGROUND" 98 | ], 99 | "Memory": "0.5GB", 100 | "Essential": "true", 101 | "Privileged": true 102 | } 103 | ] 104 | } 105 | }, 106 | "ElasticsearchDomain": { 107 | "Type": "AWS::Elasticsearch::Domain", 108 | "Properties": { 109 | "DomainName": { 110 | "Ref": "DomainName" 111 | }, 112 | "ElasticsearchVersion": { 113 | "Ref": "ElasticsearchVersion" 114 | }, 115 | "ElasticsearchClusterConfig": { 116 | "InstanceCount": "1", 117 | "InstanceType": { 118 | "Ref": "InstanceType" 119 | } 120 | }, 121 | "EBSOptions": { 122 | "EBSEnabled": "true", 123 | "Iops": 0, 124 | "VolumeSize": 10, 125 | "VolumeType": "standard" 126 | }, 127 | "SnapshotOptions": { 128 | "AutomatedSnapshotStartHour": "0" 129 | }, 130 | "AccessPolicies": { 131 | "Version": "2012-10-17", 132 | "Statement": [ 133 | { 134 | "Effect": "Deny", 135 | "Principal": { 136 | "AWS": "*" 137 | }, 138 | "Action": "es:*", 139 | "Resource": "*" 140 | } 141 | ] 142 | }, 143 | "LogPublishingOptions": { 144 | "SEARCH_SLOW_LOGS": { 145 | "CloudWatchLogsLogGroupArn": "arn:aws:logs:us-east-1:123456789012:log-group:/aws/aes/domains/es-slow-logs", 146 | "Enabled": "true" 147 | }, 148 | "INDEX_SLOW_LOGS": { 149 | "CloudWatchLogsLogGroupArn": "arn:aws:logs:us-east-1:123456789012:log-group:/aws/aes/domains/es-index-slow-logs", 150 | "Enabled": "true" 151 | } 152 | }, 153 | "AdvancedOptions": { 154 | "rest.action.multi.allow_explicit_index": "true" 155 | }, 156 | "Tags": [ 157 | { 158 | "Key": "foo", 159 | "Value": "bar" 160 | } 161 | ], 162 | "VPCOptions": { 163 | "SecurityGroupIds": [ 164 | { 165 | "Ref": "mySecurityGroup" 166 | } 167 | ] 168 | } 169 | } 170 | }, 171 | "iamPolicy": { 172 | "Type": "AWS::IAM::Policy", 173 | "Properties": { 174 | "PolicyName": "CFNUsers", 175 | "PolicyDocument": { 176 | "Version": "2012-10-17", 177 | "Statement": [ 178 | { 179 | "Effect": "Allow", 180 | "Action": [ 181 | "cloudformation:Describe*", 182 | "cloudformation:List*", 183 | "cloudformation:Get*" 184 | ], 185 | "Resource": "*" 186 | } 187 | ] 188 | }, 189 | "Users": [ 190 | { 191 | "Ref": "CFNUserGroup" 192 | } 193 | ] 194 | } 195 | }, 196 | "subscription": { 197 | "Type": "AWS::SNS::Subscription", 198 | "Properties": { 199 | "Protocol": "http" 200 | } 201 | }, 202 | "queue": { 203 | "Type": "AWS::SQS::Queue", 204 | "Properties": { 205 | "KmsMasterKeyId": "alias/aws/sqs" 206 | } 207 | }, 208 | "subnet": { 209 | "Type": "AWS::EC2::Subnet", 210 | "Properties": { 211 | "MapPublicIpOnLaunch": true 212 | } 213 | }, 214 | "securitygroup": { 215 | "Type": "AWS::EC2::SecurityGroup", 216 | "Properties": { 217 | "GroupDescription": "secg", 218 | "VpcId": "vpc-1e1af67b", 219 | "SecurityGroupIngress": [ 220 | { 221 | "IpProtocol": "tcp", 222 | "FromPort": 22, 223 | "ToPort": 22, 224 | "CidrIp": "0.0.0.0/0" 225 | } 226 | ] 227 | } 228 | }, 229 | "rdsDbinstance": { 230 | "Type": "AWS::RDS::DBInstance", 231 | "Properties": { 232 | "MultiAZ": false, 233 | "CopyTagsToSnapshot": false, 234 | "DBInstanceIdentifier": { 235 | "Ref": "DBInstanceID" 236 | }, 237 | "DBName": { 238 | "Ref": "DBName" 239 | }, 240 | "DBInstanceClass": { 241 | "Ref": "DBInstanceClass" 242 | }, 243 | "AllocatedStorage": { 244 | "Ref": "DBAllocatedStorage" 245 | }, 246 | "Engine": "MySQL", 247 | "EngineVersion": "8.0.16", 248 | "MasterUsername": { 249 | "Ref": "DBUsername" 250 | }, 251 | "MasterUserPassword": { 252 | "Ref": "DBPassword" 253 | }, 254 | "StorageEncrypted": false, 255 | "MonitoringInterval": "60", 256 | "MonitoringRoleArn": "arn:aws:iam::1233456789012:role/rds-monitoring-role", 257 | "BackupRetentionPeriod": 0, 258 | "PubliclyAccessible": true 259 | } 260 | }, 261 | "rdsEventSubscription": { 262 | "Type": "AWS::RDS::EventSubscription", 263 | "Properties": { 264 | "SourceType": "db-security-group", 265 | "Enabled": false 266 | } 267 | }, 268 | "redshiftCluster": { 269 | "Type": "AWS::Redshift::Cluster", 270 | "Properties": { 271 | "PubliclyAccessible": true, 272 | "Encrypted": false 273 | } 274 | } 275 | }, 276 | "Outputs": { 277 | "secg": { 278 | "Value": { 279 | "Ref": "secg" 280 | } 281 | } 282 | } 283 | } 284 | -------------------------------------------------------------------------------- /CFT/cft_aws_json_fixed_issues.json: -------------------------------------------------------------------------------- 1 | { 2 | "AWSTemplateFormatVersion": "2010-09-09", 3 | "Description": "Hadoop Cluster (HDP 2.3)", 4 | "Resources": { 5 | "S3Bucket": { 6 | "Type": "AWS::S3::Bucket", 7 | "Properties": { 8 | "AccessControl": "Private", 9 | "LoggingConfiguration": true, 10 | "VersioningConfiguration": { 11 | "Status": "Enabled" 12 | }, 13 | "BucketEncryption": { 14 | "ServerSideEncryptionConfiguration": [ 15 | { 16 | "ServerSideEncryptionByDefault": { 17 | "SSEAlgorithm": true 18 | } 19 | } 20 | ] 21 | }, 22 | "CorsConfiguration": { 23 | "CorsRules": [ 24 | { 25 | "AllowedHeaders": [ 26 | "*" 27 | ], 28 | "AllowedMethods": [ 29 | "GET" 30 | ], 31 | "AllowedOrigins": [ 32 | "*" 33 | ], 34 | "ExposedHeaders": [ 35 | "Date" 36 | ], 37 | "Id": "myCORSRuleId1", 38 | "MaxAge": "3600" 39 | }, 40 | { 41 | "AllowedHeaders": [ 42 | "x-amz-*" 43 | ], 44 | "AllowedMethods": [ 45 | "DELETE" 46 | ], 47 | "AllowedOrigins": [ 48 | "http://www.example1.com", 49 | "http://www.example2.com" 50 | ], 51 | "ExposedHeaders": [ 52 | "Connection", 53 | "Server", 54 | "Date" 55 | ], 56 | "Id": "myCORSRuleId2", 57 | "MaxAge": "1800" 58 | } 59 | ] 60 | } 61 | } 62 | }, 63 | "secg": { 64 | "Type": "AWS::EC2::SecurityGroup", 65 | "Properties": { 66 | "GroupDescription": "secg", 67 | "VpcId": "vpc-1e1af67b", 68 | "SecurityGroupIngress": [ 69 | { 70 | "IpProtocol": "-1", 71 | "CidrIp": "0.0.0.0/0" 72 | } 73 | ] 74 | } 75 | } 76 | }, 77 | "Outputs": { 78 | "secg": { 79 | "Value": { 80 | "Ref": "secg" 81 | } 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /CFT/cft_aws_json_with_issues.json: -------------------------------------------------------------------------------- 1 | { 2 | "AWSTemplateFormatVersion": "2010-09-09", 3 | "Description": "Hadoop Cluster (HDP 2.3)", 4 | "Resources": { 5 | "S3Bucket": { 6 | "Type": "AWS::S3::Bucket", 7 | "Properties": { 8 | "AccessControl": "PublicRead", 9 | "CorsConfiguration": { 10 | "CorsRules": [ 11 | { 12 | "AllowedHeaders": [ 13 | "*" 14 | ], 15 | "AllowedMethods": [ 16 | "GET" 17 | ], 18 | "AllowedOrigins": [ 19 | "*" 20 | ], 21 | "ExposedHeaders": [ 22 | "Date" 23 | ], 24 | "Id": "myCORSRuleId1", 25 | "MaxAge": "3600" 26 | }, 27 | { 28 | "AllowedHeaders": [ 29 | "x-amz-*" 30 | ], 31 | "AllowedMethods": [ 32 | "DELETE" 33 | ], 34 | "AllowedOrigins": [ 35 | "http://www.example1.com", 36 | "http://www.example2.com" 37 | ], 38 | "ExposedHeaders": [ 39 | "Connection", 40 | "Server", 41 | "Date" 42 | ], 43 | "Id": "myCORSRuleId2", 44 | "MaxAge": "1800" 45 | } 46 | ] 47 | } 48 | } 49 | }, 50 | "secg": { 51 | "Type": "AWS::EC2::SecurityGroup", 52 | "Properties": { 53 | "GroupDescription": "secg", 54 | "VpcId": "vpc-1e1af67b", 55 | "SecurityGroupIngress": [ 56 | { 57 | "IpProtocol": "-1", 58 | "CidrIp": "0.0.0.0/0" 59 | } 60 | ] 61 | } 62 | } 63 | }, 64 | "Outputs": { 65 | "secg": { 66 | "Value": { 67 | "Ref": "secg" 68 | } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /CFT/cft_aws_json_with_issues_variable_files.json: -------------------------------------------------------------------------------- 1 | { 2 | "AWSTemplateFormatVersion": "2010-09-09", 3 | "Description": "Hadoop Cluster (HDP 2.3)", 4 | "Parameters" : { 5 | "AccessControlFile" : { 6 | "Type" : "String" 7 | } 8 | }, 9 | "Resources": { 10 | "S3Bucket": { 11 | "Type": "AWS::S3::Bucket", 12 | "Properties": { 13 | "AccessControl": { "Ref" : "AccessControlFile" }, 14 | "LoggingConfiguration": true, 15 | "VersioningConfiguration": { 16 | "Status": "Suspended" 17 | }, 18 | "BucketEncryption": { 19 | "ServerSideEncryptionConfiguration": [ 20 | { 21 | "ServerSideEncryptionByDefault": { 22 | "SSEAlgorithm": true 23 | } 24 | } 25 | ] 26 | }, 27 | "CorsConfiguration": { 28 | "CorsRules": [ 29 | { 30 | "AllowedHeaders": [ 31 | "*" 32 | ], 33 | "AllowedMethods": [ 34 | "GET" 35 | ], 36 | "AllowedOrigins": [ 37 | "*" 38 | ], 39 | "ExposedHeaders": [ 40 | "Date" 41 | ], 42 | "Id": "myCORSRuleId1", 43 | "MaxAge": "3600" 44 | }, 45 | { 46 | "AllowedHeaders": [ 47 | "x-amz-*" 48 | ], 49 | "AllowedMethods": [ 50 | "DELETE" 51 | ], 52 | "AllowedOrigins": [ 53 | "http://www.example1.com", 54 | "http://www.example2.com" 55 | ], 56 | "ExposedHeaders": [ 57 | "Connection", 58 | "Server", 59 | "Date" 60 | ], 61 | "Id": "myCORSRuleId2", 62 | "MaxAge": "1800" 63 | } 64 | ] 65 | } 66 | } 67 | }, 68 | "secg": { 69 | "Type": "AWS::EC2::SecurityGroup", 70 | "Properties": { 71 | "GroupDescription": "secg", 72 | "VpcId": "vpc-1e1af67b", 73 | "SecurityGroupIngress": [ 74 | { 75 | "IpProtocol": "-1", 76 | "CidrIp": "0.0.0.0/0" 77 | } 78 | ] 79 | } 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /CFT/cft_aws_json_with_issues_variable_values.json: -------------------------------------------------------------------------------- 1 | { 2 | "AWSTemplateFormatVersion": "2010-09-09", 3 | "Description": "Hadoop Cluster (HDP 2.3)", 4 | "Resources": { 5 | "S3Bucket": { 6 | "Type": "AWS::S3::Bucket", 7 | "Properties": { 8 | "AccessControl": { "Ref" : "AccessControl" }, 9 | "LoggingConfiguration": true, 10 | "VersioningConfiguration": { 11 | "Status": "Enabled" 12 | }, 13 | "BucketEncryption": { 14 | "ServerSideEncryptionConfiguration": [ 15 | { 16 | "ServerSideEncryptionByDefault": { 17 | "SSEAlgorithm": true 18 | } 19 | } 20 | ] 21 | }, 22 | "CorsConfiguration": { 23 | "CorsRules": [ 24 | { 25 | "AllowedHeaders": [ 26 | "*" 27 | ], 28 | "AllowedMethods": [ 29 | "GET" 30 | ], 31 | "AllowedOrigins": [ 32 | "*" 33 | ], 34 | "ExposedHeaders": [ 35 | "Date" 36 | ], 37 | "Id": "myCORSRuleId1", 38 | "MaxAge": "3600" 39 | }, 40 | { 41 | "AllowedHeaders": [ 42 | "x-amz-*" 43 | ], 44 | "AllowedMethods": [ 45 | "DELETE" 46 | ], 47 | "AllowedOrigins": [ 48 | "http://www.example1.com", 49 | "http://www.example2.com" 50 | ], 51 | "ExposedHeaders": [ 52 | "Connection", 53 | "Server", 54 | "Date" 55 | ], 56 | "Id": "myCORSRuleId2", 57 | "MaxAge": "1800" 58 | } 59 | ] 60 | } 61 | } 62 | }, 63 | "secg": { 64 | "Type": "AWS::EC2::SecurityGroup", 65 | "Properties": { 66 | "GroupDescription": "secg", 67 | "VpcId": "vpc-1e1af67b", 68 | "SecurityGroupIngress": [ 69 | { 70 | "IpProtocol": "-1", 71 | "CidrIp": "0.0.0.0/0" 72 | } 73 | ] 74 | } 75 | } 76 | }, 77 | "Outputs": { 78 | "secg": { 79 | "Value": { 80 | "Ref": "secg" 81 | } 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /CFT/cft_variables.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "ParameterValue": "PublicRead", 4 | "ParameterKey": "AccessControlFile" 5 | } 6 | ] 7 | -------------------------------------------------------------------------------- /K8S/k8s_fixed_issues.yml: -------------------------------------------------------------------------------- 1 | kind: Deployment 2 | apiVersion: extensions/v1beta1 3 | metadata: 4 | name: yml-nginx-deployment 5 | spec: 6 | # A deployment's specification really only 7 | # has a few useful options 8 | 9 | # 1. How many copies of each pod do we want? 10 | replicas: 3 11 | 12 | # 2. How do want to update the pods? 13 | # strategy: Recreate 14 | 15 | # 3. Which pods are managed by this deployment? 16 | selector: 17 | # This must match the labels we set on the pod! 18 | matchLabels: 19 | deploy: example 20 | 21 | # This template field is a regular pod configuration 22 | # nested inside the deployment spec 23 | template: 24 | metadata: 25 | # Set labels on the pod. 26 | # This is used in the deployment selector. 27 | labels: 28 | deploy: example 29 | spec: 30 | containers: 31 | - name: nginx 32 | image: nginx:1.7.9 33 | securityContext: 34 | privileged: false -------------------------------------------------------------------------------- /K8S/k8s_with_issues.yml: -------------------------------------------------------------------------------- 1 | kind: Deployment 2 | apiVersion: extensions/v1beta1 3 | metadata: 4 | name: yml-nginx-deployment 5 | spec: 6 | # A deployment's specification really only 7 | # has a few useful options 8 | 9 | # 1. How many copies of each pod do we want? 10 | replicas: 3 11 | 12 | # 2. How do want to update the pods? 13 | # strategy: Recreate 14 | 15 | # 3. Which pods are managed by this deployment? 16 | selector: 17 | # This must match the labels we set on the pod! 18 | matchLabels: 19 | deploy: example 20 | 21 | # This template field is a regular pod configuration 22 | # nested inside the deployment spec 23 | template: 24 | metadata: 25 | # Set labels on the pod. 26 | # This is used in the deployment selector. 27 | labels: 28 | deploy: example 29 | spec: 30 | containers: 31 | - name: nginx 32 | image: nginx:1.7.9 33 | securityContext: 34 | privileged: true -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 prisma-cloud-shiftleft 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Postman Collection/README.md: -------------------------------------------------------------------------------- 1 | # Postman Collection for Async Scan Flow 2 | ## Import Postman Demo & Environment file 3 | From Postman menu, select File > Import. Then select demo file(s) and the environment file. 4 | ## Provide Environment details for API server & credentials 5 | 1. Click on Manage Environment button in top right 6 | 2. Click on the ".prismacloud.io" item in the Manage Environments popup 7 | 3. Enter values under CURRENT VALUE for **server, username, and password** 8 | 9 | - Alternatively, you can directly modify the api_server.postman_environment.json with a text editor, filling in the value fields for "server", "username", and "password", for example: 10 | ``` 11 | { 12 | "id": "064d974c-383e-47fe-b9cc-8bab0b6c8bff", 13 | "name": ".prismacloud.io", 14 | "values": [ 15 | { 16 | "key": "server", 17 | "value": "**my api server name**", 18 | "enabled": true 19 | }, 20 | { 21 | "key": "username", 22 | "value": "**my access key**", 23 | "enabled": true 24 | }, 25 | { 26 | "key": "password", 27 | "value": "**my secret key**", 28 | "enabled": true 29 | } 30 | ], 31 | "_postman_variable_scope": "environment", 32 | "_postman_exported_at": "2020-10-28T17:57:27.024Z", 33 | "_postman_exported_using": "Postman/7.34.0" 34 | } 35 | ``` 36 | ## Running Demo Collection 37 | - You can run individual API Request in sequence within the collection (as it's tagged with prefix with a number from 1 to 7) 38 | - Or run the entire collection using the Collection Runner 39 | 1. From Menu, select File > New Runner Window. 40 | 2. Select your collection name from the list. 41 | 3. Click blue Run button. 42 | -------------------------------------------------------------------------------- /Postman Collection/api_server_environment.postman_collection.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "064d974c-383e-47fe-b9cc-8bab0b6c8bff", 3 | "name": ".prismacloud.io", 4 | "values": [ 5 | { 6 | "key": "server", 7 | "value": "api2slqa.k8sdev", 8 | "enabled": true 9 | }, 10 | { 11 | "key": "username", 12 | "value": "", 13 | "enabled": true 14 | }, 15 | { 16 | "key": "password", 17 | "value": "", 18 | "enabled": true 19 | } 20 | ], 21 | "_postman_variable_scope": "environment", 22 | "_postman_exported_at": "2020-10-28T17:57:27.024Z", 23 | "_postman_exported_using": "Postman/7.34.0" 24 | } -------------------------------------------------------------------------------- /Postman Collection/cft_demo.postman_collection.json: -------------------------------------------------------------------------------- 1 | { 2 | "info": { 3 | "_postman_id": "6c230833-eeb8-44fd-a49b-2e8bcfa84649", 4 | "name": "IaC Scan API v2 - Async Microservices Demo CFT", 5 | "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" 6 | }, 7 | "item": [ 8 | { 9 | "name": "[1. Authenticate] /login", 10 | "event": [ 11 | { 12 | "listen": "test", 13 | "script": { 14 | "id": "9e2ce682-ce29-4925-92cc-c2f208f9d90c", 15 | "exec": [ 16 | "var jsonData = pm.response.json();", 17 | "pm.test(\"login_successful\", function () {", 18 | " pm.expect(jsonData.message).to.eql(\"login_successful\");", 19 | "});", 20 | "token = jsonData.token;console.log(\"x-redlock-auth is: \" + token);", 21 | "pm.environment.set(\"token\", token);", 22 | "" 23 | ], 24 | "type": "text/javascript" 25 | } 26 | }, 27 | { 28 | "listen": "prerequest", 29 | "script": { 30 | "id": "48ecd7a5-a9a0-4ef3-a3d8-97c7852e7c6d", 31 | "exec": [ 32 | "console.log(request.name);", 33 | "" 34 | ], 35 | "type": "text/javascript" 36 | } 37 | } 38 | ], 39 | "protocolProfileBehavior": { 40 | "disabledSystemHeaders": {} 41 | }, 42 | "request": { 43 | "method": "POST", 44 | "header": [], 45 | "body": { 46 | "mode": "raw", 47 | "raw": "{\"username\":\"{{username}}\",\"password\":\"{{password}}\"}", 48 | "options": { 49 | "raw": { 50 | "language": "json" 51 | } 52 | } 53 | }, 54 | "url": { 55 | "raw": "https://{{server}}.prismacloud.io/login", 56 | "protocol": "https", 57 | "host": [ 58 | "{{server}}", 59 | "prismacloud", 60 | "io" 61 | ], 62 | "path": [ 63 | "login" 64 | ] 65 | } 66 | }, 67 | "response": [] 68 | }, 69 | { 70 | "name": "[2. Initiate Scan] /iac/v2/scans", 71 | "event": [ 72 | { 73 | "listen": "test", 74 | "script": { 75 | "id": "d20458c0-7b0c-46a9-9c9b-edc5f74744c1", 76 | "exec": [ 77 | "var jsonData = pm.response.json();", 78 | "scan_id = jsonData.data.id;console.log(\"Scan ID is:[\"+scan_id+\"]\");", 79 | "s3_url = jsonData.data.links.url;console.log(\"S3 URL is:[\"+s3_url+\"]\");", 80 | "pm.globals.set(\"scan_id\", scan_id);", 81 | "pm.globals.set(\"s3_url\", s3_url);", 82 | "pm.test(\"Scan ID [\"+scan_id+\"] and S3 URL exists\", function () {", 83 | " pm.expect(jsonData.data.id).to.exist;", 84 | " pm.expect(jsonData.data.links.url).to.exist;", 85 | "});", 86 | "console.log(jsonData)", 87 | "", 88 | "" 89 | ], 90 | "type": "text/javascript" 91 | } 92 | }, 93 | { 94 | "listen": "prerequest", 95 | "script": { 96 | "id": "eea72865-65d3-45f4-976d-bb474115cfa9", 97 | "exec": [ 98 | "console.log(request.name);", 99 | "var jsonReq = JSON.parse(pm.request.body.raw);", 100 | "var assetType = jsonReq.data.attributes.assetType;", 101 | "pm.globals.set(\"assetType\", assetType);", 102 | "" 103 | ], 104 | "type": "text/javascript" 105 | } 106 | } 107 | ], 108 | "protocolProfileBehavior": { 109 | "disabledSystemHeaders": {} 110 | }, 111 | "request": { 112 | "method": "POST", 113 | "header": [ 114 | { 115 | "key": "x-redlock-auth", 116 | "type": "text", 117 | "value": "{{token}}" 118 | }, 119 | { 120 | "key": "Content-Type", 121 | "type": "text", 122 | "value": "application/vnd.api+json", 123 | "warning": "This is a duplicate header and will be overridden by the Content-Type header generated by Postman." 124 | } 125 | ], 126 | "body": { 127 | "mode": "raw", 128 | "raw": "{\n \"data\": {\n \"type\": \"async-scan\",\n \"attributes\": {\n \"assetName\": \"postman-test\",\n \"assetType\": \"IaC-API\",\n \"accessKey\": \"some_key\",\n \"tags\":\n {\n \"name\": \"env\",\n \"value\": \"prod\",\n \"source\": \"string\"\n }\n ,\n \"scanAttributes\": {\n \"buildNumber\": 9963,\n \"projectName\": \"my-project2\",\n \"prName\": \"SL-1234\",\n \"pipelineName\": \"PrismaCloudScan-Lambda\",\n \"pipelineLambda\": \"AWSCodePipeline-ng\",\n \"pipelineJobId\": \"3fa85f64-5717-4562-b3fc-2c963f66afa62\",\n \"pipelineStageName\": \"SourceArtifact2\",\n \"pipelineActionName\": \"SourceArtifact2\"\n },\n \"failureCriteria\": {\n \"high\": 1,\n \"medium\": 1,\n \"low\": 1,\n \"operator\": \"or\"\n }\n }\n }\n}", 129 | "options": { 130 | "raw": { 131 | "language": "json" 132 | } 133 | } 134 | }, 135 | "url": { 136 | "raw": "https://{{server}}.prismacloud.io/iac/v2/scans", 137 | "protocol": "https", 138 | "host": [ 139 | "{{server}}", 140 | "prismacloud", 141 | "io" 142 | ], 143 | "path": [ 144 | "iac", 145 | "v2", 146 | "scans" 147 | ] 148 | } 149 | }, 150 | "response": [] 151 | }, 152 | { 153 | "name": "[3. Upload File] CFT template file with issues", 154 | "event": [ 155 | { 156 | "listen": "test", 157 | "script": { 158 | "id": "aac1c6ea-cc2e-49a6-8bb1-3b668c9c366c", 159 | "exec": [ 160 | "var req = request.data;", 161 | "console.log(\"Uploading file to S3 URL: [\"+req.path+']')", 162 | "pm.test(\"Uploading file [\"+req.path+\"] successful\", function () {", 163 | " pm.response.to.have.status(200);", 164 | "});" 165 | ], 166 | "type": "text/javascript" 167 | } 168 | }, 169 | { 170 | "listen": "prerequest", 171 | "script": { 172 | "id": "edb5edad-af99-44dc-81ba-a3014bcb0fc1", 173 | "exec": [ 174 | "console.log(request.name);", 175 | "" 176 | ], 177 | "type": "text/javascript" 178 | } 179 | } 180 | ], 181 | "protocolProfileBehavior": { 182 | "disabledSystemHeaders": {} 183 | }, 184 | "request": { 185 | "method": "PUT", 186 | "header": [ 187 | { 188 | "key": "Content-Type", 189 | "type": "text", 190 | "value": "application/octet-stream", 191 | "warning": "This is a duplicate header and will be overridden by the Content-Type header generated by Postman." 192 | } 193 | ], 194 | "body": { 195 | "mode": "file", 196 | "file": { 197 | "src": "~/iac-samples/CFT/cft_aws_json_with_issues.json" 198 | }, 199 | "options": { 200 | "file": {} 201 | } 202 | }, 203 | "url": { 204 | "raw": "{{s3_url}}", 205 | "host": [ 206 | "{{s3_url}}" 207 | ] 208 | } 209 | }, 210 | "response": [] 211 | }, 212 | { 213 | "name": "[4. Trigger Scan] /iac/v2/scans/{{scan_id}} for CFT template", 214 | "event": [ 215 | { 216 | "listen": "test", 217 | "script": { 218 | "id": "f16e4777-ae20-4d40-bb33-3a75e8523c6f", 219 | "exec": [ 220 | "var jsonReq = JSON.parse(pm.request.body.raw);", 221 | "var templateType = jsonReq.data.attributes.templateType;", 222 | "pm.test(\"Triggered [\"+templateType+\"] Scan Successful\", function () {", 223 | " pm.response.to.have.status(200);", 224 | "});", 225 | "console.log(\"Triggered Scan for Template Type: [\"+jsonReq.data.attributes.templateType+']')" 226 | ], 227 | "type": "text/javascript" 228 | } 229 | }, 230 | { 231 | "listen": "prerequest", 232 | "script": { 233 | "id": "aa370216-cf4c-4a35-a494-a56d04f2c9f1", 234 | "exec": [ 235 | "console.log(request.name);", 236 | "" 237 | ], 238 | "type": "text/javascript" 239 | } 240 | } 241 | ], 242 | "protocolProfileBehavior": { 243 | "disabledSystemHeaders": {} 244 | }, 245 | "request": { 246 | "method": "POST", 247 | "header": [ 248 | { 249 | "key": "x-redlock-auth", 250 | "type": "text", 251 | "value": "{{token}}" 252 | }, 253 | { 254 | "key": "Content-Type", 255 | "type": "text", 256 | "value": "application/vnd.api+json", 257 | "warning": "This is a duplicate header and will be overridden by the Content-Type header generated by Postman." 258 | } 259 | ], 260 | "body": { 261 | "mode": "raw", 262 | "raw": "{\n \"data\": {\n \"id\": \"{{scan_id}}\",\n \"attributes\": {\n \"templateType\": \"cft\"\n }\n }\n}", 263 | "options": { 264 | "raw": { 265 | "language": "json" 266 | } 267 | } 268 | }, 269 | "url": { 270 | "raw": "https://{{server}}.prismacloud.io/iac/v2/scans/{{scan_id}}", 271 | "protocol": "https", 272 | "host": [ 273 | "{{server}}", 274 | "prismacloud", 275 | "io" 276 | ], 277 | "path": [ 278 | "iac", 279 | "v2", 280 | "scans", 281 | "{{scan_id}}" 282 | ] 283 | } 284 | }, 285 | "response": [] 286 | }, 287 | { 288 | "name": "[5. Check Scan Status] /iac/v2/scans/{{scan_id}}/status", 289 | "event": [ 290 | { 291 | "listen": "test", 292 | "script": { 293 | "id": "9428aa6d-bd35-48a6-9afa-3397f5b05cb1", 294 | "exec": [ 295 | "var jsonData = pm.response.json();", 296 | "var status = respJson.data.attributes.status", 297 | "pm.globals.set(\"status\", status);", 298 | "pm.test(\"Scan's status is [\"+status+\"]\", function () {", 299 | " pm.expect(jsonData.data.attributes.status).oneOf([\"passed\",\"failed\"]);", 300 | "});", 301 | "console.log(jsonData)" 302 | ], 303 | "type": "text/javascript" 304 | } 305 | }, 306 | { 307 | "listen": "prerequest", 308 | "script": { 309 | "id": "6edbabd0-09f9-4777-9f66-9623ea404af4", 310 | "exec": [ 311 | "console.log(request.name);", 312 | "var retryDelay = 1000;", 313 | "var retryLimit = 5;", 314 | "var url = request['url'].replace('{{server}}', pm.environment.get('server')).replace('{{scan_id}}', pm.globals.get('scan_id'));", 315 | "console.log(\"URL is: \"+url)", 316 | "", 317 | "const getRequest = {", 318 | " url: url,", 319 | " method: 'GET',", 320 | " header: {", 321 | " 'Content-Type': 'application/json',", 322 | " 'x-redlock-auth': pm.environment.get('token')", 323 | " }", 324 | "};", 325 | "", 326 | "function isProcessingComplete(retryCount) {", 327 | " pm.sendRequest(getRequest, function (err, response) {", 328 | " if(err) {", 329 | " console.log(\"ERR: \"+err);", 330 | " } else {", 331 | " respJson = response.json()", 332 | " if(respJson.errors != null) {", 333 | " console.log(\"Scan Status errored: \"+respJson.errors);", 334 | " } else if(respJson.errors != null || respJson.data.attributes.status == 'processing') {", 335 | " console.log(respJson);", 336 | " if (retryCount < retryLimit) {", 337 | " console.log('IaC Scan Job is still processing. Retrying in ' + retryDelay + 'ms');", 338 | " setTimeout(function() {", 339 | " isProcessingComplete(++retryCount);", 340 | " }, retryDelay);", 341 | " } else {", 342 | " console.log('Retry limit reached, giving up.');", 343 | " postman.setNextRequest(null);", 344 | " }", 345 | " } else {", 346 | " console.log('Scan Status is: ['+respJson.data.attributes.status+']');", 347 | " }", 348 | " }", 349 | " });", 350 | "}", 351 | "", 352 | "isProcessingComplete(1);" 353 | ], 354 | "type": "text/javascript" 355 | } 356 | } 357 | ], 358 | "protocolProfileBehavior": { 359 | "disabledSystemHeaders": {} 360 | }, 361 | "request": { 362 | "method": "GET", 363 | "header": [ 364 | { 365 | "key": "x-redlock-auth", 366 | "type": "text", 367 | "value": "{{token}}" 368 | }, 369 | { 370 | "key": "Content-Type", 371 | "type": "text", 372 | "value": "application/vnd.api+json" 373 | } 374 | ], 375 | "url": { 376 | "raw": "https://{{server}}.prismacloud.io/iac/v2/scans/{{scan_id}}/status", 377 | "protocol": "https", 378 | "host": [ 379 | "{{server}}", 380 | "prismacloud", 381 | "io" 382 | ], 383 | "path": [ 384 | "iac", 385 | "v2", 386 | "scans", 387 | "{{scan_id}}", 388 | "status" 389 | ], 390 | "query": [ 391 | { 392 | "key": "scanId", 393 | "value": "{{scan_id}}", 394 | "disabled": true 395 | } 396 | ] 397 | } 398 | }, 399 | "response": [] 400 | }, 401 | { 402 | "name": "[6. Get Scan Result] /iac/v2/scans/{{scan_id}}/results", 403 | "event": [ 404 | { 405 | "listen": "test", 406 | "script": { 407 | "id": "85633370-d7a7-4505-90ae-7e36fe441083", 408 | "exec": [ 409 | "var jsonData = pm.response.json();", 410 | "var statusEnv=pm.globals.get(\"status\")", 411 | "", 412 | "policyMap = new Map()", 413 | "policyArr = jsonData.data", 414 | "resultArr = []", 415 | "for(var i=0; i< policyArr.length; i++) {", 416 | " policyMap.set(policyArr[i].id, policyArr[i].attributes)", 417 | " resultArr.push(policyArr[i].attributes.name)", 418 | "}", 419 | "pm.test(\"Scan Result's 'matchedPoliciesSummary' is [\"+JSON.stringify(jsonData.meta.matchedPoliciesSummary)+\"]\", function () {", 420 | " pm.expect(jsonData.meta.matchedPoliciesSummary).exist;", 421 | "});", 422 | "pm.test(\"Scan Result's is [\"+statusEnv+\"] due to [\"+policyMap.size+\"] Matched Policies\", function () {", 423 | " pm.expect(jsonData.meta.matchedPoliciesSummary).exist;", 424 | " if (statusEnv == \"failed\") {", 425 | " pm.expect(policyMap.size).gt(0);", 426 | " console.log(policyMap)", 427 | " } else {", 428 | " pm.expect(policyMap.size).eq(0);", 429 | " console.log(\"else\")", 430 | " }", 431 | "});", 432 | "", 433 | "for(var i=0; i< resultArr.length; i++) {", 434 | " console.log(resultArr[i])", 435 | " pm.test(\"Matched Policy #\"+(i+1)+\": [\"+resultArr[i]+\"]\", function () {", 436 | " pm.expect(resultArr[i]).exist;", 437 | " });", 438 | "}", 439 | "", 440 | "console.log(\"matchedPoliciesSummary:\")", 441 | "console.log(jsonData.meta.matchedPoliciesSummary)", 442 | "console.log(jsonData)" 443 | ], 444 | "type": "text/javascript" 445 | } 446 | }, 447 | { 448 | "listen": "prerequest", 449 | "script": { 450 | "id": "c19a29a5-37ce-44cd-86fe-d8cc7a28b05e", 451 | "exec": [ 452 | "console.log(request.name);", 453 | "" 454 | ], 455 | "type": "text/javascript" 456 | } 457 | } 458 | ], 459 | "protocolProfileBehavior": { 460 | "disabledSystemHeaders": {} 461 | }, 462 | "request": { 463 | "method": "GET", 464 | "header": [ 465 | { 466 | "key": "x-redlock-auth", 467 | "type": "text", 468 | "value": "{{token}}" 469 | }, 470 | { 471 | "key": "Content-Type", 472 | "type": "text", 473 | "value": "application/vnd.api+json" 474 | } 475 | ], 476 | "url": { 477 | "raw": "https://{{server}}.prismacloud.io/iac/v2/scans/{{scan_id}}/results", 478 | "protocol": "https", 479 | "host": [ 480 | "{{server}}", 481 | "prismacloud", 482 | "io" 483 | ], 484 | "path": [ 485 | "iac", 486 | "v2", 487 | "scans", 488 | "{{scan_id}}", 489 | "results" 490 | ], 491 | "query": [ 492 | { 493 | "key": "scanId", 494 | "value": "{{scan_id}}", 495 | "disabled": true 496 | } 497 | ] 498 | } 499 | }, 500 | "response": [] 501 | }, 502 | { 503 | "name": "[7. Get Scan Details] iac/v2/scans/{{scan_id}}", 504 | "event": [ 505 | { 506 | "listen": "test", 507 | "script": { 508 | "id": "4db9ccb4-c795-4403-bb64-25d97fd93c3b", 509 | "exec": [ 510 | "var jsonData = pm.response.json();", 511 | "var assetTypeEnv = pm.globals.get(\"assetType\")", 512 | "pm.test(\"Scan Metadata 'failureCriteria' is [\"+JSON.stringify(jsonData.data.attributes.failureCriteria)+\"]\", function () {", 513 | " pm.expect(jsonData.data.attributes.failureCriteria).exist;", 514 | "});", 515 | "pm.test(\"Scan Metadata 'asset type' matches: [\"+assetTypeEnv+\"]\", function () {", 516 | " pm.expect(jsonData.data.attributes.type).contains(assetTypeEnv);", 517 | "});", 518 | "pm.test(\"Scan Metadata 'tags' is [\"+JSON.stringify(jsonData.data.attributes.tags)+\"]\", function () {", 519 | " pm.expect(jsonData.data.attributes.tags).exist;", 520 | "});", 521 | "console.log(\"assetType: \"+jsonData.data.attributes.type)", 522 | "console.log(\"failureCriteria: \"+jsonData.data.attributes.failureCriteria)", 523 | "console.log(\"tags: \"+JSON.stringify(jsonData.data.attributes.tags))", 524 | "console.log(jsonData)" 525 | ], 526 | "type": "text/javascript" 527 | } 528 | }, 529 | { 530 | "listen": "prerequest", 531 | "script": { 532 | "id": "2dcd6d4e-6ca3-4485-9c93-eb2fb598a397", 533 | "exec": [ 534 | "console.log(request.name);", 535 | "" 536 | ], 537 | "type": "text/javascript" 538 | } 539 | } 540 | ], 541 | "protocolProfileBehavior": { 542 | "disabledSystemHeaders": {} 543 | }, 544 | "request": { 545 | "method": "GET", 546 | "header": [ 547 | { 548 | "key": "x-redlock-auth", 549 | "type": "text", 550 | "value": "{{token}}" 551 | }, 552 | { 553 | "key": "Content-Type", 554 | "type": "text", 555 | "value": "application/vnd.api+json" 556 | } 557 | ], 558 | "url": { 559 | "raw": "https://{{server}}.prismacloud.io/iac/v2/scans/{{scan_id}}", 560 | "protocol": "https", 561 | "host": [ 562 | "{{server}}", 563 | "prismacloud", 564 | "io" 565 | ], 566 | "path": [ 567 | "iac", 568 | "v2", 569 | "scans", 570 | "{{scan_id}}" 571 | ], 572 | "query": [ 573 | { 574 | "key": "scanId", 575 | "value": "{{scan_id}}", 576 | "disabled": true 577 | } 578 | ] 579 | } 580 | }, 581 | "response": [] 582 | } 583 | ], 584 | "protocolProfileBehavior": {} 585 | } -------------------------------------------------------------------------------- /Postman Collection/k8s_demo.postman_collection.json: -------------------------------------------------------------------------------- 1 | { 2 | "info": { 3 | "_postman_id": "a73e9e3b-e843-41f7-8c78-b246472afe60", 4 | "name": "IaC Scan API v2 - Async Microservices Demo K8S", 5 | "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" 6 | }, 7 | "item": [ 8 | { 9 | "name": "[1. Authenticate] /login", 10 | "event": [ 11 | { 12 | "listen": "test", 13 | "script": { 14 | "id": "43cb6081-8c91-4fdc-ac4c-3a51360c0344", 15 | "exec": [ 16 | "var jsonData = pm.response.json();", 17 | "pm.test(\"login_successful\", function () {", 18 | " pm.expect(jsonData.message).to.eql(\"login_successful\");", 19 | "});", 20 | "token = jsonData.token;console.log(\"x-redlock-auth is: \" + token);", 21 | "pm.environment.set(\"token\", token);", 22 | "" 23 | ], 24 | "type": "text/javascript" 25 | } 26 | }, 27 | { 28 | "listen": "prerequest", 29 | "script": { 30 | "id": "ae33e3b2-ca11-4475-bb75-a29d22b8a775", 31 | "exec": [ 32 | "console.log(request.name);", 33 | "" 34 | ], 35 | "type": "text/javascript" 36 | } 37 | } 38 | ], 39 | "protocolProfileBehavior": { 40 | "disabledSystemHeaders": {} 41 | }, 42 | "request": { 43 | "method": "POST", 44 | "header": [], 45 | "body": { 46 | "mode": "raw", 47 | "raw": "{\"username\":\"{{username}}\",\"password\":\"{{password}}\"}", 48 | "options": { 49 | "raw": { 50 | "language": "json" 51 | } 52 | } 53 | }, 54 | "url": { 55 | "raw": "https://{{server}}.prismacloud.io/login", 56 | "protocol": "https", 57 | "host": [ 58 | "{{server}}", 59 | "prismacloud", 60 | "io" 61 | ], 62 | "path": [ 63 | "login" 64 | ] 65 | } 66 | }, 67 | "response": [] 68 | }, 69 | { 70 | "name": "[2. Initiate Scan] /iac/v2/scans", 71 | "event": [ 72 | { 73 | "listen": "test", 74 | "script": { 75 | "id": "c79e6a3f-3a4c-458c-9654-b9e7b96866fb", 76 | "exec": [ 77 | "var jsonData = pm.response.json();", 78 | "scan_id = jsonData.data.id;console.log(\"Scan ID is:[\"+scan_id+\"]\");", 79 | "s3_url = jsonData.data.links.url;console.log(\"S3 URL is:[\"+s3_url+\"]\");", 80 | "pm.globals.set(\"scan_id\", scan_id);", 81 | "pm.globals.set(\"s3_url\", s3_url);", 82 | "pm.test(\"Scan ID [\"+scan_id+\"] and S3 URL exists\", function () {", 83 | " pm.expect(jsonData.data.id).to.exist;", 84 | " pm.expect(jsonData.data.links.url).to.exist;", 85 | "});", 86 | "console.log(jsonData)", 87 | "", 88 | "" 89 | ], 90 | "type": "text/javascript" 91 | } 92 | }, 93 | { 94 | "listen": "prerequest", 95 | "script": { 96 | "id": "5d98b533-3d78-4879-8d62-d36860afcd9a", 97 | "exec": [ 98 | "console.log(request.name);", 99 | "var jsonReq = JSON.parse(pm.request.body.raw);", 100 | "var assetType = jsonReq.data.attributes.assetType;", 101 | "pm.globals.set(\"assetType\", assetType);", 102 | "" 103 | ], 104 | "type": "text/javascript" 105 | } 106 | } 107 | ], 108 | "protocolProfileBehavior": { 109 | "disabledSystemHeaders": {} 110 | }, 111 | "request": { 112 | "method": "POST", 113 | "header": [ 114 | { 115 | "key": "x-redlock-auth", 116 | "type": "text", 117 | "value": "{{token}}" 118 | }, 119 | { 120 | "key": "Content-Type", 121 | "type": "text", 122 | "value": "application/vnd.api+json", 123 | "warning": "This is a duplicate header and will be overridden by the Content-Type header generated by Postman." 124 | } 125 | ], 126 | "body": { 127 | "mode": "raw", 128 | "raw": "{\n \"data\": {\n \"type\": \"async-scan\",\n \"attributes\": {\n \"assetName\": \"postman-test\",\n \"assetType\": \"IaC-API\",\n \"accessKey\": \"some_key\",\n \"tags\":\n {\n \"name\": \"env\",\n \"value\": \"prod\",\n \"source\": \"string\"\n }\n ,\n \"scanAttributes\": {\n \"buildNumber\": 9963,\n \"projectName\": \"my-project2\",\n \"prName\": \"SL-1234\",\n \"pipelineName\": \"PrismaCloudScan-Lambda\",\n \"pipelineLambda\": \"AWSCodePipeline-ng\",\n \"pipelineJobId\": \"3fa85f64-5717-4562-b3fc-2c963f66afa62\",\n \"pipelineStageName\": \"SourceArtifact2\",\n \"pipelineActionName\": \"SourceArtifact2\"\n },\n \"failureCriteria\": {\n \"high\": 1,\n \"medium\": 1,\n \"low\": 1,\n \"operator\": \"or\"\n }\n }\n }\n}", 129 | "options": { 130 | "raw": { 131 | "language": "json" 132 | } 133 | } 134 | }, 135 | "url": { 136 | "raw": "https://{{server}}.prismacloud.io/iac/v2/scans", 137 | "protocol": "https", 138 | "host": [ 139 | "{{server}}", 140 | "prismacloud", 141 | "io" 142 | ], 143 | "path": [ 144 | "iac", 145 | "v2", 146 | "scans" 147 | ] 148 | } 149 | }, 150 | "response": [] 151 | }, 152 | { 153 | "name": "[3. Upload File] K8S template file with issues", 154 | "event": [ 155 | { 156 | "listen": "test", 157 | "script": { 158 | "id": "f445f8f3-8f3c-40f1-b72a-c7e276a97b01", 159 | "exec": [ 160 | "var req = request.data;", 161 | "console.log(\"Uploading file to S3 URL: [\"+req.path+']')", 162 | "pm.test(\"Uploading file [\"+req.path+\"] successful\", function () {", 163 | " pm.response.to.have.status(200);", 164 | "});" 165 | ], 166 | "type": "text/javascript" 167 | } 168 | }, 169 | { 170 | "listen": "prerequest", 171 | "script": { 172 | "id": "9094afc0-4afa-47cc-ac21-d53dbaf69efc", 173 | "exec": [ 174 | "console.log(request.name);", 175 | "" 176 | ], 177 | "type": "text/javascript" 178 | } 179 | } 180 | ], 181 | "protocolProfileBehavior": { 182 | "disabledSystemHeaders": {} 183 | }, 184 | "request": { 185 | "method": "PUT", 186 | "header": [ 187 | { 188 | "key": "Content-Type", 189 | "type": "text", 190 | "value": "application/octet-stream", 191 | "warning": "This is a duplicate header and will be overridden by the Content-Type header generated by Postman." 192 | } 193 | ], 194 | "body": { 195 | "mode": "file", 196 | "file": { 197 | "src": "~/iac-samples/K8S/k8s_with_issues.yml" 198 | }, 199 | "options": { 200 | "file": {} 201 | } 202 | }, 203 | "url": { 204 | "raw": "{{s3_url}}", 205 | "host": [ 206 | "{{s3_url}}" 207 | ] 208 | } 209 | }, 210 | "response": [] 211 | }, 212 | { 213 | "name": "[4. Trigger Scan] /iac/v2/scans/{{scan_id}} for K8S template", 214 | "event": [ 215 | { 216 | "listen": "test", 217 | "script": { 218 | "id": "71933ca9-7dec-40cd-bc89-a031c2b1be98", 219 | "exec": [ 220 | "var jsonReq = JSON.parse(pm.request.body.raw);", 221 | "var templateType = jsonReq.data.attributes.templateType;", 222 | "pm.test(\"Triggered [\"+templateType+\"] Scan Successful\", function () {", 223 | " pm.response.to.have.status(200);", 224 | "});", 225 | "console.log(\"Triggered Scan for Template Type: [\"+jsonReq.data.attributes.templateType+']')" 226 | ], 227 | "type": "text/javascript" 228 | } 229 | }, 230 | { 231 | "listen": "prerequest", 232 | "script": { 233 | "id": "5d6528c3-32df-45fe-a636-acb4e6469a96", 234 | "exec": [ 235 | "console.log(request.name);", 236 | "" 237 | ], 238 | "type": "text/javascript" 239 | } 240 | } 241 | ], 242 | "protocolProfileBehavior": { 243 | "disabledSystemHeaders": {} 244 | }, 245 | "request": { 246 | "method": "POST", 247 | "header": [ 248 | { 249 | "key": "x-redlock-auth", 250 | "type": "text", 251 | "value": "{{token}}" 252 | }, 253 | { 254 | "key": "Content-Type", 255 | "type": "text", 256 | "value": "application/vnd.api+json", 257 | "warning": "This is a duplicate header and will be overridden by the Content-Type header generated by Postman." 258 | } 259 | ], 260 | "body": { 261 | "mode": "raw", 262 | "raw": "{\n \"data\": {\n \"id\": \"{{scan_id}}\",\n \"attributes\": {\n \"templateType\": \"k8s\"\n }\n }\n}", 263 | "options": { 264 | "raw": { 265 | "language": "json" 266 | } 267 | } 268 | }, 269 | "url": { 270 | "raw": "https://{{server}}.prismacloud.io/iac/v2/scans/{{scan_id}}", 271 | "protocol": "https", 272 | "host": [ 273 | "{{server}}", 274 | "prismacloud", 275 | "io" 276 | ], 277 | "path": [ 278 | "iac", 279 | "v2", 280 | "scans", 281 | "{{scan_id}}" 282 | ] 283 | } 284 | }, 285 | "response": [] 286 | }, 287 | { 288 | "name": "[5. Check Scan Status] /iac/v2/scans/{{scan_id}}/status", 289 | "event": [ 290 | { 291 | "listen": "test", 292 | "script": { 293 | "id": "5fe021e8-cfbd-43cf-8424-bf5077119719", 294 | "exec": [ 295 | "var jsonData = pm.response.json();", 296 | "var status = respJson.data.attributes.status", 297 | "pm.globals.set(\"status\", status);", 298 | "pm.test(\"Scan's status is [\"+status+\"]\", function () {", 299 | " pm.expect(jsonData.data.attributes.status).oneOf([\"passed\",\"failed\"]);", 300 | "});", 301 | "console.log(jsonData)" 302 | ], 303 | "type": "text/javascript" 304 | } 305 | }, 306 | { 307 | "listen": "prerequest", 308 | "script": { 309 | "id": "fbcede04-f9b0-4ab9-8214-1cf41c8a64f7", 310 | "exec": [ 311 | "console.log(request.name);", 312 | "var retryDelay = 2000;", 313 | "var retryLimit = 10;", 314 | "var url = request['url'].replace('{{server}}', pm.environment.get('server')).replace('{{scan_id}}', pm.globals.get('scan_id'));", 315 | "console.log(\"URL is: \"+url)", 316 | "", 317 | "const getRequest = {", 318 | " url: url,", 319 | " method: 'GET',", 320 | " header: {", 321 | " 'Content-Type': 'application/json',", 322 | " 'x-redlock-auth': pm.environment.get('token')", 323 | " }", 324 | "};", 325 | "", 326 | "function isProcessingComplete(retryCount) {", 327 | " pm.sendRequest(getRequest, function (err, response) {", 328 | " if(err) {", 329 | " console.log(\"ERR: \"+err);", 330 | " } else {", 331 | " respJson = response.json()", 332 | " if(respJson.errors != null) {", 333 | " console.log(\"Scan Status errored: \"+respJson.errors);", 334 | " } else if(respJson.errors != null || respJson.data.attributes.status == 'processing') {", 335 | " console.log(respJson);", 336 | " if (retryCount < retryLimit) {", 337 | " console.log('IaC Scan Job is still processing. Retrying in ' + retryDelay + 'ms');", 338 | " setTimeout(function() {", 339 | " isProcessingComplete(++retryCount);", 340 | " }, retryDelay);", 341 | " } else {", 342 | " console.log('Retry limit reached, giving up.');", 343 | " postman.setNextRequest(null);", 344 | " }", 345 | " } else {", 346 | " console.log('Scan Status is: ['+respJson.data.attributes.status+']');", 347 | " }", 348 | " }", 349 | " });", 350 | "}", 351 | "", 352 | "isProcessingComplete(1);" 353 | ], 354 | "type": "text/javascript" 355 | } 356 | } 357 | ], 358 | "protocolProfileBehavior": { 359 | "disabledSystemHeaders": {} 360 | }, 361 | "request": { 362 | "method": "GET", 363 | "header": [ 364 | { 365 | "key": "x-redlock-auth", 366 | "type": "text", 367 | "value": "{{token}}" 368 | }, 369 | { 370 | "key": "Content-Type", 371 | "type": "text", 372 | "value": "application/vnd.api+json" 373 | } 374 | ], 375 | "url": { 376 | "raw": "https://{{server}}.prismacloud.io/iac/v2/scans/{{scan_id}}/status", 377 | "protocol": "https", 378 | "host": [ 379 | "{{server}}", 380 | "prismacloud", 381 | "io" 382 | ], 383 | "path": [ 384 | "iac", 385 | "v2", 386 | "scans", 387 | "{{scan_id}}", 388 | "status" 389 | ], 390 | "query": [ 391 | { 392 | "key": "scanId", 393 | "value": "{{scan_id}}", 394 | "disabled": true 395 | } 396 | ] 397 | } 398 | }, 399 | "response": [] 400 | }, 401 | { 402 | "name": "[6. Get Scan Result] /iac/v2/scans/{{scan_id}}/results", 403 | "event": [ 404 | { 405 | "listen": "test", 406 | "script": { 407 | "id": "e3cd57dd-3419-4879-8937-787f9b335bd2", 408 | "exec": [ 409 | "var jsonData = pm.response.json();", 410 | "var statusEnv=pm.globals.get(\"status\")", 411 | "", 412 | "policyMap = new Map()", 413 | "policyArr = jsonData.data", 414 | "resultArr = []", 415 | "for(var i=0; i< policyArr.length; i++) {", 416 | " policyMap.set(policyArr[i].id, policyArr[i].attributes)", 417 | " resultArr.push(policyArr[i].attributes.name)", 418 | "}", 419 | "pm.test(\"Scan Result's 'matchedPoliciesSummary' is [\"+JSON.stringify(jsonData.meta.matchedPoliciesSummary)+\"]\", function () {", 420 | " pm.expect(jsonData.meta.matchedPoliciesSummary).exist;", 421 | "});", 422 | "pm.test(\"Scan Result's is [\"+statusEnv+\"] due to [\"+policyMap.size+\"] Matched Policies\", function () {", 423 | " pm.expect(jsonData.meta.matchedPoliciesSummary).exist;", 424 | " if (statusEnv == \"failed\") {", 425 | " pm.expect(policyMap.size).gt(0);", 426 | " console.log(policyMap)", 427 | " } else {", 428 | " pm.expect(policyMap.size).eq(0);", 429 | " console.log(\"else\")", 430 | " }", 431 | "});", 432 | "", 433 | "for(var i=0; i< resultArr.length; i++) {", 434 | " console.log(resultArr[i])", 435 | " pm.test(\"Matched Policy #\"+(i+1)+\": [\"+resultArr[i]+\"]\", function () {", 436 | " pm.expect(resultArr[i]).exist;", 437 | " });", 438 | "}", 439 | "", 440 | "console.log(\"matchedPoliciesSummary:\")", 441 | "console.log(jsonData.meta.matchedPoliciesSummary)", 442 | "console.log(jsonData)" 443 | ], 444 | "type": "text/javascript" 445 | } 446 | }, 447 | { 448 | "listen": "prerequest", 449 | "script": { 450 | "id": "e5cea659-5141-48c5-bb03-ed41f901f4cd", 451 | "exec": [ 452 | "console.log(request.name);", 453 | "" 454 | ], 455 | "type": "text/javascript" 456 | } 457 | } 458 | ], 459 | "protocolProfileBehavior": { 460 | "disabledSystemHeaders": {} 461 | }, 462 | "request": { 463 | "method": "GET", 464 | "header": [ 465 | { 466 | "key": "x-redlock-auth", 467 | "type": "text", 468 | "value": "{{token}}" 469 | }, 470 | { 471 | "key": "Content-Type", 472 | "type": "text", 473 | "value": "application/vnd.api+json" 474 | } 475 | ], 476 | "url": { 477 | "raw": "https://{{server}}.prismacloud.io/iac/v2/scans/{{scan_id}}/results", 478 | "protocol": "https", 479 | "host": [ 480 | "{{server}}", 481 | "prismacloud", 482 | "io" 483 | ], 484 | "path": [ 485 | "iac", 486 | "v2", 487 | "scans", 488 | "{{scan_id}}", 489 | "results" 490 | ], 491 | "query": [ 492 | { 493 | "key": "scanId", 494 | "value": "{{scan_id}}", 495 | "disabled": true 496 | } 497 | ] 498 | } 499 | }, 500 | "response": [] 501 | }, 502 | { 503 | "name": "[7. Get Scan Details] iac/v2/scans/{{scan_id}}", 504 | "event": [ 505 | { 506 | "listen": "test", 507 | "script": { 508 | "id": "f311ee6a-a2b2-4a2a-8148-a32cef68c191", 509 | "exec": [ 510 | "var jsonData = pm.response.json();", 511 | "var assetTypeEnv = pm.globals.get(\"assetType\")", 512 | "pm.test(\"Scan Metadata 'failureCriteria' is [\"+JSON.stringify(jsonData.data.attributes.failureCriteria)+\"]\", function () {", 513 | " pm.expect(jsonData.data.attributes.failureCriteria).exist;", 514 | "});", 515 | "pm.test(\"Scan Metadata 'asset type' matches: [\"+assetTypeEnv+\"]\", function () {", 516 | " pm.expect(jsonData.data.attributes.type).contains(assetTypeEnv);", 517 | "});", 518 | "pm.test(\"Scan Metadata 'tags' is [\"+JSON.stringify(jsonData.data.attributes.tags)+\"]\", function () {", 519 | " pm.expect(jsonData.data.attributes.tags).exist;", 520 | "});", 521 | "console.log(\"assetType: \"+jsonData.data.attributes.type)", 522 | "console.log(\"failureCriteria: \"+jsonData.data.attributes.failureCriteria)", 523 | "console.log(\"tags: \"+JSON.stringify(jsonData.data.attributes.tags))", 524 | "console.log(jsonData)" 525 | ], 526 | "type": "text/javascript" 527 | } 528 | }, 529 | { 530 | "listen": "prerequest", 531 | "script": { 532 | "id": "6ed61426-e615-4c8e-b3a5-1c9950d33774", 533 | "exec": [ 534 | "console.log(request.name);", 535 | "" 536 | ], 537 | "type": "text/javascript" 538 | } 539 | } 540 | ], 541 | "protocolProfileBehavior": { 542 | "disabledSystemHeaders": {} 543 | }, 544 | "request": { 545 | "method": "GET", 546 | "header": [ 547 | { 548 | "key": "x-redlock-auth", 549 | "type": "text", 550 | "value": "{{token}}" 551 | }, 552 | { 553 | "key": "Content-Type", 554 | "type": "text", 555 | "value": "application/vnd.api+json" 556 | } 557 | ], 558 | "url": { 559 | "raw": "https://{{server}}.prismacloud.io/iac/v2/scans/{{scan_id}}", 560 | "protocol": "https", 561 | "host": [ 562 | "{{server}}", 563 | "prismacloud", 564 | "io" 565 | ], 566 | "path": [ 567 | "iac", 568 | "v2", 569 | "scans", 570 | "{{scan_id}}" 571 | ], 572 | "query": [ 573 | { 574 | "key": "scanId", 575 | "value": "{{scan_id}}", 576 | "disabled": true 577 | } 578 | ] 579 | } 580 | }, 581 | "response": [] 582 | } 583 | ], 584 | "protocolProfileBehavior": {} 585 | } -------------------------------------------------------------------------------- /Postman Collection/tf12_demo.postman_collection.json: -------------------------------------------------------------------------------- 1 | { 2 | "info": { 3 | "_postman_id": "c5c60e24-88b3-4562-94c9-8073f3c1ce47", 4 | "name": "IaC Scan API v2 - Async Microservices Demo TF", 5 | "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" 6 | }, 7 | "item": [ 8 | { 9 | "name": "[1. Authenticate] /login", 10 | "event": [ 11 | { 12 | "listen": "test", 13 | "script": { 14 | "id": "f0a65c03-3105-423d-b027-a094331f940a", 15 | "exec": [ 16 | "var jsonData = pm.response.json();", 17 | "pm.test(\"login_successful\", function () {", 18 | " pm.expect(jsonData.message).to.eql(\"login_successful\");", 19 | "});", 20 | "token = jsonData.token;console.log(\"x-redlock-auth is: \" + token);", 21 | "pm.environment.set(\"token\", token);", 22 | "" 23 | ], 24 | "type": "text/javascript" 25 | } 26 | }, 27 | { 28 | "listen": "prerequest", 29 | "script": { 30 | "id": "35870111-bf3a-45c6-8330-27c2356aa348", 31 | "exec": [ 32 | "console.log(request.name);", 33 | "" 34 | ], 35 | "type": "text/javascript" 36 | } 37 | } 38 | ], 39 | "protocolProfileBehavior": { 40 | "disabledSystemHeaders": {} 41 | }, 42 | "request": { 43 | "method": "POST", 44 | "header": [], 45 | "body": { 46 | "mode": "raw", 47 | "raw": "{\"username\":\"{{username}}\",\"password\":\"{{password}}\"}", 48 | "options": { 49 | "raw": { 50 | "language": "json" 51 | } 52 | } 53 | }, 54 | "url": { 55 | "raw": "https://{{server}}.prismacloud.io/login", 56 | "protocol": "https", 57 | "host": [ 58 | "{{server}}", 59 | "prismacloud", 60 | "io" 61 | ], 62 | "path": [ 63 | "login" 64 | ] 65 | } 66 | }, 67 | "response": [] 68 | }, 69 | { 70 | "name": "[2. Initiate Scan] /iac/v2/scans", 71 | "event": [ 72 | { 73 | "listen": "test", 74 | "script": { 75 | "id": "b276517f-1fbe-41dd-8b14-cc82af131842", 76 | "exec": [ 77 | "var jsonData = pm.response.json();", 78 | "scan_id = jsonData.data.id;console.log(\"Scan ID is:[\"+scan_id+\"]\");", 79 | "s3_url = jsonData.data.links.url;console.log(\"S3 URL is:[\"+s3_url+\"]\");", 80 | "pm.globals.set(\"scan_id\", scan_id);", 81 | "pm.globals.set(\"s3_url\", s3_url);", 82 | "pm.test(\"Scan ID [\"+scan_id+\"] and S3 URL exists\", function () {", 83 | " pm.expect(jsonData.data.id).to.exist;", 84 | " pm.expect(jsonData.data.links.url).to.exist;", 85 | "});", 86 | "console.log(jsonData)", 87 | "", 88 | "" 89 | ], 90 | "type": "text/javascript" 91 | } 92 | }, 93 | { 94 | "listen": "prerequest", 95 | "script": { 96 | "id": "0f77b7a0-1d00-4d33-b54d-713678c19057", 97 | "exec": [ 98 | "console.log(request.name);", 99 | "var jsonReq = JSON.parse(pm.request.body.raw);", 100 | "var assetType = jsonReq.data.attributes.assetType;", 101 | "pm.globals.set(\"assetType\", assetType);", 102 | "" 103 | ], 104 | "type": "text/javascript" 105 | } 106 | } 107 | ], 108 | "protocolProfileBehavior": { 109 | "disabledSystemHeaders": {} 110 | }, 111 | "request": { 112 | "method": "POST", 113 | "header": [ 114 | { 115 | "key": "x-redlock-auth", 116 | "type": "text", 117 | "value": "{{token}}" 118 | }, 119 | { 120 | "key": "Content-Type", 121 | "type": "text", 122 | "value": "application/vnd.api+json", 123 | "warning": "This is a duplicate header and will be overridden by the Content-Type header generated by Postman." 124 | } 125 | ], 126 | "body": { 127 | "mode": "raw", 128 | "raw": "{\n \"data\": {\n \"type\": \"async-scan\",\n \"attributes\": {\n \"assetName\": \"postman-test\",\n \"assetType\": \"IaC-API\",\n \"accessKey\": \"some_key\",\n \"tags\":\n {\n \"name\": \"env\",\n \"value\": \"prod\",\n \"source\": \"string\"\n }\n ,\n \"scanAttributes\": {\n \"buildNumber\": 9963,\n \"projectName\": \"my-project2\",\n \"prName\": \"SL-1234\",\n \"pipelineName\": \"PrismaCloudScan-Lambda\",\n \"pipelineLambda\": \"AWSCodePipeline-ng\",\n \"pipelineJobId\": \"3fa85f64-5717-4562-b3fc-2c963f66afa62\",\n \"pipelineStageName\": \"SourceArtifact2\",\n \"pipelineActionName\": \"SourceArtifact2\"\n },\n \"failureCriteria\": {\n \"high\": 1,\n \"medium\": 1,\n \"low\": 1,\n \"operator\": \"or\"\n }\n }\n }\n}", 129 | "options": { 130 | "raw": { 131 | "language": "json" 132 | } 133 | } 134 | }, 135 | "url": { 136 | "raw": "https://{{server}}.prismacloud.io/iac/v2/scans", 137 | "protocol": "https", 138 | "host": [ 139 | "{{server}}", 140 | "prismacloud", 141 | "io" 142 | ], 143 | "path": [ 144 | "iac", 145 | "v2", 146 | "scans" 147 | ] 148 | } 149 | }, 150 | "response": [] 151 | }, 152 | { 153 | "name": "[3. Upload File] TF template file with issues", 154 | "event": [ 155 | { 156 | "listen": "test", 157 | "script": { 158 | "id": "d52f5869-d083-4e82-8b55-519feebf4412", 159 | "exec": [ 160 | "var req = request.data;", 161 | "console.log(\"Uploading file to S3 URL: [\"+req.path+']')", 162 | "pm.test(\"Uploading file [\"+req.path+\"] successful\", function () {", 163 | " pm.response.to.have.status(200);", 164 | "});" 165 | ], 166 | "type": "text/javascript" 167 | } 168 | }, 169 | { 170 | "listen": "prerequest", 171 | "script": { 172 | "id": "177e9a77-fb7e-441f-8e30-2ca20d5a41aa", 173 | "exec": [ 174 | "console.log(request.name);", 175 | "" 176 | ], 177 | "type": "text/javascript" 178 | } 179 | } 180 | ], 181 | "protocolProfileBehavior": { 182 | "disabledSystemHeaders": {} 183 | }, 184 | "request": { 185 | "method": "PUT", 186 | "header": [ 187 | { 188 | "key": "Content-Type", 189 | "type": "text", 190 | "value": "application/octet-stream", 191 | "warning": "This is a duplicate header and will be overridden by the Content-Type header generated by Postman." 192 | } 193 | ], 194 | "body": { 195 | "mode": "file", 196 | "file": { 197 | "src": "~/iac-samples/TF/tf12_with_issues.tf" 198 | }, 199 | "options": { 200 | "file": {} 201 | } 202 | }, 203 | "url": { 204 | "raw": "{{s3_url}}", 205 | "host": [ 206 | "{{s3_url}}" 207 | ] 208 | } 209 | }, 210 | "response": [] 211 | }, 212 | { 213 | "name": "[4. Trigger Scan] /iac/v2/scans/{{scan_id}} for TF template", 214 | "event": [ 215 | { 216 | "listen": "test", 217 | "script": { 218 | "id": "51a6d129-c03c-45da-b910-d18aefa32620", 219 | "exec": [ 220 | "var jsonReq = JSON.parse(pm.request.body.raw);", 221 | "var templateType = jsonReq.data.attributes.templateType;", 222 | "pm.test(\"Triggered [\"+templateType+\"] Scan Successful\", function () {", 223 | " pm.response.to.have.status(200);", 224 | "});", 225 | "console.log(\"Triggered Scan for Template Type: [\"+jsonReq.data.attributes.templateType+']')" 226 | ], 227 | "type": "text/javascript" 228 | } 229 | }, 230 | { 231 | "listen": "prerequest", 232 | "script": { 233 | "id": "f0aded9a-c7a3-462f-85cd-2d15bfac86b7", 234 | "exec": [ 235 | "console.log(request.name);", 236 | "" 237 | ], 238 | "type": "text/javascript" 239 | } 240 | } 241 | ], 242 | "protocolProfileBehavior": { 243 | "disabledSystemHeaders": {} 244 | }, 245 | "request": { 246 | "method": "POST", 247 | "header": [ 248 | { 249 | "key": "x-redlock-auth", 250 | "type": "text", 251 | "value": "{{token}}" 252 | }, 253 | { 254 | "key": "Content-Type", 255 | "type": "text", 256 | "value": "application/vnd.api+json", 257 | "warning": "This is a duplicate header and will be overridden by the Content-Type header generated by Postman." 258 | } 259 | ], 260 | "body": { 261 | "mode": "raw", 262 | "raw": "{\n \"data\": {\n \"id\": \"{{scan_id}}\",\n \"attributes\": {\n \"templateType\": \"tf\"\n }\n }\n}", 263 | "options": { 264 | "raw": { 265 | "language": "json" 266 | } 267 | } 268 | }, 269 | "url": { 270 | "raw": "https://{{server}}.prismacloud.io/iac/v2/scans/{{scan_id}}", 271 | "protocol": "https", 272 | "host": [ 273 | "{{server}}", 274 | "prismacloud", 275 | "io" 276 | ], 277 | "path": [ 278 | "iac", 279 | "v2", 280 | "scans", 281 | "{{scan_id}}" 282 | ] 283 | } 284 | }, 285 | "response": [] 286 | }, 287 | { 288 | "name": "[5. Check Scan Status] /iac/v2/scans/{{scan_id}}/status", 289 | "event": [ 290 | { 291 | "listen": "test", 292 | "script": { 293 | "id": "8e89c14c-cbb3-46ef-acba-1f10c4693c4b", 294 | "exec": [ 295 | "var jsonData = pm.response.json();", 296 | "var status = respJson.data.attributes.status", 297 | "pm.globals.set(\"status\", status);", 298 | "pm.test(\"Scan's status is [\"+status+\"]\", function () {", 299 | " pm.expect(jsonData.data.attributes.status).oneOf([\"passed\",\"failed\"]);", 300 | "});", 301 | "console.log(jsonData)" 302 | ], 303 | "type": "text/javascript" 304 | } 305 | }, 306 | { 307 | "listen": "prerequest", 308 | "script": { 309 | "id": "7310c161-3502-48fb-8c2f-d9013524575f", 310 | "exec": [ 311 | "console.log(request.name);", 312 | "var retryDelay = 2000;", 313 | "var retryLimit = 10;", 314 | "var url = request['url'].replace('{{server}}', pm.environment.get('server')).replace('{{scan_id}}', pm.globals.get('scan_id'));", 315 | "console.log(\"URL is: \"+url)", 316 | "", 317 | "const getRequest = {", 318 | " url: url,", 319 | " method: 'GET',", 320 | " header: {", 321 | " 'Content-Type': 'application/json',", 322 | " 'x-redlock-auth': pm.environment.get('token')", 323 | " }", 324 | "};", 325 | "", 326 | "function isProcessingComplete(retryCount) {", 327 | " pm.sendRequest(getRequest, function (err, response) {", 328 | " if(err) {", 329 | " console.log(\"ERR: \"+err);", 330 | " } else {", 331 | " respJson = response.json()", 332 | " if(respJson.errors != null) {", 333 | " console.log(\"Scan Status errored: \"+respJson.errors);", 334 | " } else if(respJson.errors != null || respJson.data.attributes.status == 'processing') {", 335 | " console.log(respJson);", 336 | " if (retryCount < retryLimit) {", 337 | " console.log('IaC Scan Job is still processing. Retrying in ' + retryDelay + 'ms');", 338 | " setTimeout(function() {", 339 | " isProcessingComplete(++retryCount);", 340 | " }, retryDelay);", 341 | " } else {", 342 | " console.log('Retry limit reached, giving up.');", 343 | " postman.setNextRequest(null);", 344 | " }", 345 | " } else {", 346 | " console.log('Scan Status is: ['+respJson.data.attributes.status+']');", 347 | " }", 348 | " }", 349 | " });", 350 | "}", 351 | "", 352 | "isProcessingComplete(1);" 353 | ], 354 | "type": "text/javascript" 355 | } 356 | } 357 | ], 358 | "protocolProfileBehavior": { 359 | "disabledSystemHeaders": {} 360 | }, 361 | "request": { 362 | "method": "GET", 363 | "header": [ 364 | { 365 | "key": "x-redlock-auth", 366 | "type": "text", 367 | "value": "{{token}}" 368 | }, 369 | { 370 | "key": "Content-Type", 371 | "type": "text", 372 | "value": "application/vnd.api+json" 373 | } 374 | ], 375 | "url": { 376 | "raw": "https://{{server}}.prismacloud.io/iac/v2/scans/{{scan_id}}/status", 377 | "protocol": "https", 378 | "host": [ 379 | "{{server}}", 380 | "prismacloud", 381 | "io" 382 | ], 383 | "path": [ 384 | "iac", 385 | "v2", 386 | "scans", 387 | "{{scan_id}}", 388 | "status" 389 | ], 390 | "query": [ 391 | { 392 | "key": "scanId", 393 | "value": "{{scan_id}}", 394 | "disabled": true 395 | } 396 | ] 397 | } 398 | }, 399 | "response": [] 400 | }, 401 | { 402 | "name": "[6. Get Scan Result] /iac/v2/scans/{{scan_id}}/results", 403 | "event": [ 404 | { 405 | "listen": "test", 406 | "script": { 407 | "id": "000479f3-ae17-4ef2-99c9-233d5d93cb9e", 408 | "exec": [ 409 | "var jsonData = pm.response.json();", 410 | "var statusEnv=pm.globals.get(\"status\")", 411 | "", 412 | "policyMap = new Map()", 413 | "policyArr = jsonData.data", 414 | "resultArr = []", 415 | "for(var i=0; i< policyArr.length; i++) {", 416 | " policyMap.set(policyArr[i].id, policyArr[i].attributes)", 417 | " resultArr.push(policyArr[i].attributes.name)", 418 | "}", 419 | "pm.test(\"Scan Result's 'matchedPoliciesSummary' is [\"+JSON.stringify(jsonData.meta.matchedPoliciesSummary)+\"]\", function () {", 420 | " pm.expect(jsonData.meta.matchedPoliciesSummary).exist;", 421 | "});", 422 | "pm.test(\"Scan Result's is [\"+statusEnv+\"] due to [\"+policyMap.size+\"] Matched Policies\", function () {", 423 | " pm.expect(jsonData.meta.matchedPoliciesSummary).exist;", 424 | " if (statusEnv == \"failed\") {", 425 | " pm.expect(policyMap.size).gt(0);", 426 | " console.log(policyMap)", 427 | " } else {", 428 | " pm.expect(policyMap.size).eq(0);", 429 | " console.log(\"else\")", 430 | " }", 431 | "});", 432 | "", 433 | "for(var i=0; i< resultArr.length; i++) {", 434 | " console.log(resultArr[i])", 435 | " pm.test(\"Matched Policy #\"+(i+1)+\": [\"+resultArr[i]+\"]\", function () {", 436 | " pm.expect(resultArr[i]).exist;", 437 | " });", 438 | "}", 439 | "", 440 | "console.log(\"matchedPoliciesSummary:\")", 441 | "console.log(jsonData.meta.matchedPoliciesSummary)", 442 | "console.log(jsonData)" 443 | ], 444 | "type": "text/javascript" 445 | } 446 | }, 447 | { 448 | "listen": "prerequest", 449 | "script": { 450 | "id": "fb420701-356f-4f68-90ec-b4ecaab3d2c0", 451 | "exec": [ 452 | "console.log(request.name);", 453 | "" 454 | ], 455 | "type": "text/javascript" 456 | } 457 | } 458 | ], 459 | "protocolProfileBehavior": { 460 | "disabledSystemHeaders": {} 461 | }, 462 | "request": { 463 | "method": "GET", 464 | "header": [ 465 | { 466 | "key": "x-redlock-auth", 467 | "type": "text", 468 | "value": "{{token}}" 469 | }, 470 | { 471 | "key": "Content-Type", 472 | "type": "text", 473 | "value": "application/vnd.api+json" 474 | } 475 | ], 476 | "url": { 477 | "raw": "https://{{server}}.prismacloud.io/iac/v2/scans/{{scan_id}}/results", 478 | "protocol": "https", 479 | "host": [ 480 | "{{server}}", 481 | "prismacloud", 482 | "io" 483 | ], 484 | "path": [ 485 | "iac", 486 | "v2", 487 | "scans", 488 | "{{scan_id}}", 489 | "results" 490 | ], 491 | "query": [ 492 | { 493 | "key": "scanId", 494 | "value": "{{scan_id}}", 495 | "disabled": true 496 | } 497 | ] 498 | } 499 | }, 500 | "response": [] 501 | }, 502 | { 503 | "name": "[7. Get Scan Details] iac/v2/scans/{{scan_id}}", 504 | "event": [ 505 | { 506 | "listen": "test", 507 | "script": { 508 | "id": "e765e3cf-f967-4729-8ac4-58d1d4adb286", 509 | "exec": [ 510 | "var jsonData = pm.response.json();", 511 | "var assetTypeEnv = pm.globals.get(\"assetType\")", 512 | "pm.test(\"Scan Metadata 'failureCriteria' is [\"+JSON.stringify(jsonData.data.attributes.failureCriteria)+\"]\", function () {", 513 | " pm.expect(jsonData.data.attributes.failureCriteria).exist;", 514 | "});", 515 | "pm.test(\"Scan Metadata 'asset type' matches: [\"+assetTypeEnv+\"]\", function () {", 516 | " pm.expect(jsonData.data.attributes.type).contains(assetTypeEnv);", 517 | "});", 518 | "pm.test(\"Scan Metadata 'tags' is [\"+JSON.stringify(jsonData.data.attributes.tags)+\"]\", function () {", 519 | " pm.expect(jsonData.data.attributes.tags).exist;", 520 | "});", 521 | "console.log(\"assetType: \"+jsonData.data.attributes.type)", 522 | "console.log(\"failureCriteria: \"+jsonData.data.attributes.failureCriteria)", 523 | "console.log(\"tags: \"+JSON.stringify(jsonData.data.attributes.tags))", 524 | "console.log(jsonData)" 525 | ], 526 | "type": "text/javascript" 527 | } 528 | }, 529 | { 530 | "listen": "prerequest", 531 | "script": { 532 | "id": "ee840a5b-e0a3-4dea-a727-36d8eded7e91", 533 | "exec": [ 534 | "console.log(request.name);", 535 | "" 536 | ], 537 | "type": "text/javascript" 538 | } 539 | } 540 | ], 541 | "protocolProfileBehavior": { 542 | "disabledSystemHeaders": {} 543 | }, 544 | "request": { 545 | "method": "GET", 546 | "header": [ 547 | { 548 | "key": "x-redlock-auth", 549 | "type": "text", 550 | "value": "{{token}}" 551 | }, 552 | { 553 | "key": "Content-Type", 554 | "type": "text", 555 | "value": "application/vnd.api+json" 556 | } 557 | ], 558 | "url": { 559 | "raw": "https://{{server}}.prismacloud.io/iac/v2/scans/{{scan_id}}", 560 | "protocol": "https", 561 | "host": [ 562 | "{{server}}", 563 | "prismacloud", 564 | "io" 565 | ], 566 | "path": [ 567 | "iac", 568 | "v2", 569 | "scans", 570 | "{{scan_id}}" 571 | ], 572 | "query": [ 573 | { 574 | "key": "scanId", 575 | "value": "{{scan_id}}", 576 | "disabled": true 577 | } 578 | ] 579 | } 580 | }, 581 | "response": [] 582 | } 583 | ], 584 | "protocolProfileBehavior": {} 585 | } -------------------------------------------------------------------------------- /Postman Collection/tfplan_demo.postman_collection.json: -------------------------------------------------------------------------------- 1 | { 2 | "info": { 3 | "_postman_id": "0f3e835f-a19f-40f8-a8b9-976ac3fca5a4", 4 | "name": "IaC Scan API v2 - Async Microservices Demo TF PLAN JSON", 5 | "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" 6 | }, 7 | "item": [ 8 | { 9 | "name": "[1. Authenticate] /login", 10 | "event": [ 11 | { 12 | "listen": "test", 13 | "script": { 14 | "id": "4c583892-1cf4-417a-b640-73b799c6fdcc", 15 | "exec": [ 16 | "var jsonData = pm.response.json();", 17 | "pm.test(\"login_successful\", function () {", 18 | " pm.expect(jsonData.message).to.eql(\"login_successful\");", 19 | "});", 20 | "token = jsonData.token;console.log(\"x-redlock-auth is: \" + token);", 21 | "pm.environment.set(\"token\", token);", 22 | "" 23 | ], 24 | "type": "text/javascript" 25 | } 26 | }, 27 | { 28 | "listen": "prerequest", 29 | "script": { 30 | "id": "ce565bf2-90b2-4d46-899b-1738eeedfaf5", 31 | "exec": [ 32 | "console.log(request.name);", 33 | "" 34 | ], 35 | "type": "text/javascript" 36 | } 37 | } 38 | ], 39 | "protocolProfileBehavior": { 40 | "disabledSystemHeaders": {} 41 | }, 42 | "request": { 43 | "method": "POST", 44 | "header": [], 45 | "body": { 46 | "mode": "raw", 47 | "raw": "{\"username\":\"{{username}}\",\"password\":\"{{password}}\"}", 48 | "options": { 49 | "raw": { 50 | "language": "json" 51 | } 52 | } 53 | }, 54 | "url": { 55 | "raw": "https://{{server}}.prismacloud.io/login", 56 | "protocol": "https", 57 | "host": [ 58 | "{{server}}", 59 | "prismacloud", 60 | "io" 61 | ], 62 | "path": [ 63 | "login" 64 | ] 65 | } 66 | }, 67 | "response": [] 68 | }, 69 | { 70 | "name": "[2. Initiate Scan] /iac/v2/scans", 71 | "event": [ 72 | { 73 | "listen": "test", 74 | "script": { 75 | "id": "0a0435fe-8140-42d7-b8ae-4c20b3a12dd6", 76 | "exec": [ 77 | "var jsonData = pm.response.json();", 78 | "scan_id = jsonData.data.id;console.log(\"Scan ID is:[\"+scan_id+\"]\");", 79 | "s3_url = jsonData.data.links.url;console.log(\"S3 URL is:[\"+s3_url+\"]\");", 80 | "pm.globals.set(\"scan_id\", scan_id);", 81 | "pm.globals.set(\"s3_url\", s3_url);", 82 | "pm.test(\"Scan ID [\"+scan_id+\"] and S3 URL exists\", function () {", 83 | " pm.expect(jsonData.data.id).to.exist;", 84 | " pm.expect(jsonData.data.links.url).to.exist;", 85 | "});", 86 | "console.log(jsonData)", 87 | "", 88 | "" 89 | ], 90 | "type": "text/javascript" 91 | } 92 | }, 93 | { 94 | "listen": "prerequest", 95 | "script": { 96 | "id": "50a93f2a-fdb0-41e3-b507-b4d7f0691dd0", 97 | "exec": [ 98 | "console.log(request.name);", 99 | "var jsonReq = JSON.parse(pm.request.body.raw);", 100 | "var assetType = jsonReq.data.attributes.assetType;", 101 | "pm.globals.set(\"assetType\", assetType);", 102 | "" 103 | ], 104 | "type": "text/javascript" 105 | } 106 | } 107 | ], 108 | "protocolProfileBehavior": { 109 | "disabledSystemHeaders": {} 110 | }, 111 | "request": { 112 | "method": "POST", 113 | "header": [ 114 | { 115 | "key": "x-redlock-auth", 116 | "type": "text", 117 | "value": "{{token}}" 118 | }, 119 | { 120 | "key": "Content-Type", 121 | "type": "text", 122 | "value": "application/vnd.api+json", 123 | "warning": "This is a duplicate header and will be overridden by the Content-Type header generated by Postman." 124 | } 125 | ], 126 | "body": { 127 | "mode": "raw", 128 | "raw": "{\n \"data\": {\n \"type\": \"async-scan\",\n \"attributes\": {\n \"assetName\": \"postman-test\",\n \"assetType\": \"IaC-API\",\n \"accessKey\": \"some_key\",\n \"tags\":\n {\n \"name\": \"env\",\n \"value\": \"prod\",\n \"source\": \"string\"\n }\n ,\n \"scanAttributes\": {\n \"buildNumber\": 9963,\n \"projectName\": \"my-project2\",\n \"prName\": \"SL-1234\",\n \"pipelineName\": \"PrismaCloudScan-Lambda\",\n \"pipelineLambda\": \"AWSCodePipeline-ng\",\n \"pipelineJobId\": \"3fa85f64-5717-4562-b3fc-2c963f66afa62\",\n \"pipelineStageName\": \"SourceArtifact2\",\n \"pipelineActionName\": \"SourceArtifact2\"\n },\n \"failureCriteria\": {\n \"high\": 1,\n \"medium\": 1,\n \"low\": 1,\n \"operator\": \"or\"\n }\n }\n }\n}", 129 | "options": { 130 | "raw": { 131 | "language": "json" 132 | } 133 | } 134 | }, 135 | "url": { 136 | "raw": "https://{{server}}.prismacloud.io/iac/v2/scans", 137 | "protocol": "https", 138 | "host": [ 139 | "{{server}}", 140 | "prismacloud", 141 | "io" 142 | ], 143 | "path": [ 144 | "iac", 145 | "v2", 146 | "scans" 147 | ] 148 | } 149 | }, 150 | "response": [] 151 | }, 152 | { 153 | "name": "[3. Upload File] TF Plan Json file", 154 | "event": [ 155 | { 156 | "listen": "test", 157 | "script": { 158 | "id": "eed0b65b-3a89-42b9-b576-59ead14cd033", 159 | "exec": [ 160 | "var req = request.data;", 161 | "console.log(\"Uploading file to S3 URL: [\"+req.path+']')", 162 | "pm.test(\"Uploading file [\"+req.path+\"] successful\", function () {", 163 | " pm.response.to.have.status(200);", 164 | "});" 165 | ], 166 | "type": "text/javascript" 167 | } 168 | }, 169 | { 170 | "listen": "prerequest", 171 | "script": { 172 | "id": "61788634-a841-43ac-8ad8-11a5766b7f6a", 173 | "exec": [ 174 | "console.log(request.name);", 175 | "" 176 | ], 177 | "type": "text/javascript" 178 | } 179 | } 180 | ], 181 | "protocolProfileBehavior": { 182 | "disabledSystemHeaders": {} 183 | }, 184 | "request": { 185 | "method": "PUT", 186 | "header": [ 187 | { 188 | "key": "Content-Type", 189 | "type": "text", 190 | "value": "application/octet-stream", 191 | "warning": "This is a duplicate header and will be overridden by the Content-Type header generated by Postman." 192 | } 193 | ], 194 | "body": { 195 | "mode": "file", 196 | "file": { 197 | "src": "~/iac-samples/TF_Plan/tfplan.json" 198 | }, 199 | "options": { 200 | "file": {} 201 | } 202 | }, 203 | "url": { 204 | "raw": "{{s3_url}}", 205 | "host": [ 206 | "{{s3_url}}" 207 | ] 208 | } 209 | }, 210 | "response": [] 211 | }, 212 | { 213 | "name": "[4. Trigger Scan] /iac/v2/scans/{{scan_id}} for TF template", 214 | "event": [ 215 | { 216 | "listen": "test", 217 | "script": { 218 | "id": "0f1aa149-511f-44d6-9a1c-1404540b5fec", 219 | "exec": [ 220 | "var jsonReq = JSON.parse(pm.request.body.raw);", 221 | "var templateType = jsonReq.data.attributes.templateType;", 222 | "pm.test(\"Triggered [\"+templateType+\"] Scan Successful\", function () {", 223 | " pm.response.to.have.status(200);", 224 | "});", 225 | "console.log(\"Triggered Scan for Template Type: [\"+jsonReq.data.attributes.templateType+']')" 226 | ], 227 | "type": "text/javascript" 228 | } 229 | }, 230 | { 231 | "listen": "prerequest", 232 | "script": { 233 | "id": "1e08f674-ac86-49d0-b1be-7d5ba9e171eb", 234 | "exec": [ 235 | "console.log(request.name);", 236 | "" 237 | ], 238 | "type": "text/javascript" 239 | } 240 | } 241 | ], 242 | "protocolProfileBehavior": { 243 | "disabledSystemHeaders": {} 244 | }, 245 | "request": { 246 | "method": "POST", 247 | "header": [ 248 | { 249 | "key": "x-redlock-auth", 250 | "type": "text", 251 | "value": "{{token}}" 252 | }, 253 | { 254 | "key": "Content-Type", 255 | "type": "text", 256 | "value": "application/vnd.api+json", 257 | "warning": "This is a duplicate header and will be overridden by the Content-Type header generated by Postman." 258 | } 259 | ], 260 | "body": { 261 | "mode": "raw", 262 | "raw": "{\n \"data\": {\n \"id\": \"{{scan_id}}\",\n \"attributes\": {\n \"templateType\": \"tf\"\n }\n }\n}", 263 | "options": { 264 | "raw": { 265 | "language": "json" 266 | } 267 | } 268 | }, 269 | "url": { 270 | "raw": "https://{{server}}.prismacloud.io/iac/v2/scans/{{scan_id}}", 271 | "protocol": "https", 272 | "host": [ 273 | "{{server}}", 274 | "prismacloud", 275 | "io" 276 | ], 277 | "path": [ 278 | "iac", 279 | "v2", 280 | "scans", 281 | "{{scan_id}}" 282 | ] 283 | } 284 | }, 285 | "response": [] 286 | }, 287 | { 288 | "name": "[5. Check Scan Status] /iac/v2/scans/{{scan_id}}/status", 289 | "event": [ 290 | { 291 | "listen": "test", 292 | "script": { 293 | "id": "bf7559a0-3727-4ea5-b9dc-715c74f0fe9d", 294 | "exec": [ 295 | "var jsonData = pm.response.json();", 296 | "var status = respJson.data.attributes.status", 297 | "pm.globals.set(\"status\", status);", 298 | "pm.test(\"Scan's status is [\"+status+\"]\", function () {", 299 | " pm.expect(jsonData.data.attributes.status).oneOf([\"passed\",\"failed\"]);", 300 | "});", 301 | "console.log(jsonData)" 302 | ], 303 | "type": "text/javascript" 304 | } 305 | }, 306 | { 307 | "listen": "prerequest", 308 | "script": { 309 | "id": "d028e0ac-7336-43c8-8a34-39940f393960", 310 | "exec": [ 311 | "console.log(request.name);", 312 | "var retryDelay = 1000;", 313 | "var retryLimit = 5;", 314 | "var url = request['url'].replace('{{server}}', pm.environment.get('server')).replace('{{scan_id}}', pm.globals.get('scan_id'));", 315 | "console.log(\"URL is: \"+url)", 316 | "", 317 | "const getRequest = {", 318 | " url: url,", 319 | " method: 'GET',", 320 | " header: {", 321 | " 'Content-Type': 'application/json',", 322 | " 'x-redlock-auth': pm.environment.get('token')", 323 | " }", 324 | "};", 325 | "", 326 | "function isProcessingComplete(retryCount) {", 327 | " pm.sendRequest(getRequest, function (err, response) {", 328 | " if(err) {", 329 | " console.log(\"ERR: \"+err);", 330 | " } else {", 331 | " respJson = response.json()", 332 | " if(respJson.errors != null) {", 333 | " console.log(\"Scan Status errored: \"+respJson.errors);", 334 | " } else if(respJson.errors != null || respJson.data.attributes.status == 'processing') {", 335 | " console.log(respJson);", 336 | " if (retryCount < retryLimit) {", 337 | " console.log('IaC Scan Job is still processing. Retrying in ' + retryDelay + 'ms');", 338 | " setTimeout(function() {", 339 | " isProcessingComplete(++retryCount);", 340 | " }, retryDelay);", 341 | " } else {", 342 | " console.log('Retry limit reached, giving up.');", 343 | " postman.setNextRequest(null);", 344 | " }", 345 | " } else {", 346 | " console.log('Scan Status is: ['+respJson.data.attributes.status+']');", 347 | " }", 348 | " }", 349 | " });", 350 | "}", 351 | "", 352 | "isProcessingComplete(1);" 353 | ], 354 | "type": "text/javascript" 355 | } 356 | } 357 | ], 358 | "protocolProfileBehavior": { 359 | "disabledSystemHeaders": {} 360 | }, 361 | "request": { 362 | "method": "GET", 363 | "header": [ 364 | { 365 | "key": "x-redlock-auth", 366 | "type": "text", 367 | "value": "{{token}}" 368 | }, 369 | { 370 | "key": "Content-Type", 371 | "type": "text", 372 | "value": "application/vnd.api+json" 373 | } 374 | ], 375 | "url": { 376 | "raw": "https://{{server}}.prismacloud.io/iac/v2/scans/{{scan_id}}/status", 377 | "protocol": "https", 378 | "host": [ 379 | "{{server}}", 380 | "prismacloud", 381 | "io" 382 | ], 383 | "path": [ 384 | "iac", 385 | "v2", 386 | "scans", 387 | "{{scan_id}}", 388 | "status" 389 | ], 390 | "query": [ 391 | { 392 | "key": "scanId", 393 | "value": "{{scan_id}}", 394 | "disabled": true 395 | } 396 | ] 397 | } 398 | }, 399 | "response": [] 400 | }, 401 | { 402 | "name": "[6. Get Scan Result] /iac/v2/scans/{{scan_id}}/results", 403 | "event": [ 404 | { 405 | "listen": "test", 406 | "script": { 407 | "id": "e0833340-ba88-45df-89b1-7bea1322a805", 408 | "exec": [ 409 | "var jsonData = pm.response.json();", 410 | "var statusEnv=pm.globals.get(\"status\")", 411 | "", 412 | "policyMap = new Map()", 413 | "policyArr = jsonData.data", 414 | "resultArr = []", 415 | "for(var i=0; i< policyArr.length; i++) {", 416 | " policyMap.set(policyArr[i].id, policyArr[i].attributes)", 417 | " resultArr.push(policyArr[i].attributes.name)", 418 | "}", 419 | "pm.test(\"Scan Result's 'matchedPoliciesSummary' is [\"+JSON.stringify(jsonData.meta.matchedPoliciesSummary)+\"]\", function () {", 420 | " pm.expect(jsonData.meta.matchedPoliciesSummary).exist;", 421 | "});", 422 | "pm.test(\"Scan Result's is [\"+statusEnv+\"] due to [\"+policyMap.size+\"] Matched Policies\", function () {", 423 | " pm.expect(jsonData.meta.matchedPoliciesSummary).exist;", 424 | " if (statusEnv == \"failed\") {", 425 | " pm.expect(policyMap.size).gt(0);", 426 | " console.log(policyMap)", 427 | " } else {", 428 | " pm.expect(policyMap.size).eq(0);", 429 | " console.log(\"else\")", 430 | " }", 431 | "});", 432 | "", 433 | "for(var i=0; i< resultArr.length; i++) {", 434 | " console.log(resultArr[i])", 435 | " pm.test(\"Matched Policy #\"+(i+1)+\": [\"+resultArr[i]+\"]\", function () {", 436 | " pm.expect(resultArr[i]).exist;", 437 | " });", 438 | "}", 439 | "", 440 | "console.log(\"matchedPoliciesSummary:\")", 441 | "console.log(jsonData.meta.matchedPoliciesSummary)", 442 | "console.log(jsonData)" 443 | ], 444 | "type": "text/javascript" 445 | } 446 | }, 447 | { 448 | "listen": "prerequest", 449 | "script": { 450 | "id": "4594c9af-778c-40ff-bbed-c7f886fe14a8", 451 | "exec": [ 452 | "console.log(request.name);", 453 | "" 454 | ], 455 | "type": "text/javascript" 456 | } 457 | } 458 | ], 459 | "protocolProfileBehavior": { 460 | "disabledSystemHeaders": {} 461 | }, 462 | "request": { 463 | "method": "GET", 464 | "header": [ 465 | { 466 | "key": "x-redlock-auth", 467 | "type": "text", 468 | "value": "{{token}}" 469 | }, 470 | { 471 | "key": "Content-Type", 472 | "type": "text", 473 | "value": "application/vnd.api+json" 474 | } 475 | ], 476 | "url": { 477 | "raw": "https://{{server}}.prismacloud.io/iac/v2/scans/{{scan_id}}/results", 478 | "protocol": "https", 479 | "host": [ 480 | "{{server}}", 481 | "prismacloud", 482 | "io" 483 | ], 484 | "path": [ 485 | "iac", 486 | "v2", 487 | "scans", 488 | "{{scan_id}}", 489 | "results" 490 | ], 491 | "query": [ 492 | { 493 | "key": "scanId", 494 | "value": "{{scan_id}}", 495 | "disabled": true 496 | } 497 | ] 498 | } 499 | }, 500 | "response": [] 501 | }, 502 | { 503 | "name": "[7. Get Scan Details] iac/v2/scans/{{scan_id}}", 504 | "event": [ 505 | { 506 | "listen": "test", 507 | "script": { 508 | "id": "aefe80d5-635a-4698-a681-d6a3cf9882ea", 509 | "exec": [ 510 | "var jsonData = pm.response.json();", 511 | "var assetTypeEnv = pm.globals.get(\"assetType\")", 512 | "pm.test(\"Scan Metadata 'failureCriteria' is [\"+JSON.stringify(jsonData.data.attributes.failureCriteria)+\"]\", function () {", 513 | " pm.expect(jsonData.data.attributes.failureCriteria).exist;", 514 | "});", 515 | "pm.test(\"Scan Metadata 'asset type' matches: [\"+assetTypeEnv+\"]\", function () {", 516 | " pm.expect(jsonData.data.attributes.type).contains(assetTypeEnv);", 517 | "});", 518 | "pm.test(\"Scan Metadata 'tags' is [\"+JSON.stringify(jsonData.data.attributes.tags)+\"]\", function () {", 519 | " pm.expect(jsonData.data.attributes.tags).exist;", 520 | "});", 521 | "console.log(\"assetType: \"+jsonData.data.attributes.type)", 522 | "console.log(\"failureCriteria: \"+jsonData.data.attributes.failureCriteria)", 523 | "console.log(\"tags: \"+JSON.stringify(jsonData.data.attributes.tags))", 524 | "console.log(jsonData)" 525 | ], 526 | "type": "text/javascript" 527 | } 528 | }, 529 | { 530 | "listen": "prerequest", 531 | "script": { 532 | "id": "3f49b197-f24a-4c1f-bbfb-cf7b24222844", 533 | "exec": [ 534 | "console.log(request.name);", 535 | "" 536 | ], 537 | "type": "text/javascript" 538 | } 539 | } 540 | ], 541 | "protocolProfileBehavior": { 542 | "disabledSystemHeaders": {} 543 | }, 544 | "request": { 545 | "method": "GET", 546 | "header": [ 547 | { 548 | "key": "x-redlock-auth", 549 | "type": "text", 550 | "value": "{{token}}" 551 | }, 552 | { 553 | "key": "Content-Type", 554 | "type": "text", 555 | "value": "application/vnd.api+json" 556 | } 557 | ], 558 | "url": { 559 | "raw": "https://{{server}}.prismacloud.io/iac/v2/scans/{{scan_id}}", 560 | "protocol": "https", 561 | "host": [ 562 | "{{server}}", 563 | "prismacloud", 564 | "io" 565 | ], 566 | "path": [ 567 | "iac", 568 | "v2", 569 | "scans", 570 | "{{scan_id}}" 571 | ], 572 | "query": [ 573 | { 574 | "key": "scanId", 575 | "value": "{{scan_id}}", 576 | "disabled": true 577 | } 578 | ] 579 | } 580 | }, 581 | "response": [] 582 | } 583 | ], 584 | "protocolProfileBehavior": {} 585 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # iac-samples 2 | Terraform, CloudFormation and Kubernetes samples 3 | -------------------------------------------------------------------------------- /TF/tf12_aws_all_issues/tf12_aws_all_issues.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.12.0" 3 | } 4 | 5 | provider "aws" { 6 | region = "us-east-1" 7 | } 8 | 9 | resource "aws_s3_bucket" "log_bucket" { 10 | bucket = "my-tf-log-bucket" 11 | acl = "log-delivery-write" 12 | } 13 | resource "aws_s3_bucket" "foo" { 14 | // 23. AWS S3 buckets are accessible to public (high) 15 | // $.resource[*].aws_s3_bucket exists and ($.resource[*].aws_s3_bucket.*[*].*.acl anyEqual public-read-write or $.resource[*].aws_s3_bucket.*[*].*.acl anyEqual public-read) 16 | acl = "public-read-write" 17 | 18 | bucket = "foo_name" 19 | // 24. AWS S3 Object Versioning is disabled (medium) 20 | // $.resource[*].aws_s3_bucket exists and ($.resource[*].aws_s3_bucket.*[*].*.versioning[*].enabled does not exist or $.resource[*].aws_s3_bucket.*[*].*.versioning[*].enabled anyFalse) 21 | versioning { 22 | enabled = false 23 | } 24 | // 1. AWS S3 CloudTrail buckets for which access logging is disabled () 25 | // $.resource[*].aws_cloudtrail[*].*[*].enable_logging anyFalse 26 | // UPDATED Policy: "AWS Access logging not enabled on S3 buckets" 27 | // $.resource.aws_s3_bucket exists and ($.resource.aws_s3_bucket[*].logging anyNull or $.resource.aws_s3_bucket[*].logging[*].target_bucket !exists or $.resource.aws_s3_bucket[*].logging[*].target_bucket anyNull) 28 | logging { 29 | target_bucket = aws_s3_bucket.log_bucket.id 30 | target_prefix = "log/" 31 | } 32 | } 33 | 34 | resource "aws_cloudtrail" "foo_cloudtrail" { 35 | // 2. AWS CloudTrail bucket is publicly accessible (high) 36 | // $.resource[*].aws_cloudtrail exists and $.resource[*].aws_cloudtrail[*].*[*].s3_bucket_name equals $.resource[*].aws_s3_bucket_public_access_block[*].*[*].bucket and ($.resource[*].aws_s3_bucket_public_access_block[*].*[*].block_public_acls isFalse or $.resource[*].aws_s3_bucket_public_access_block[*].*[*].block_public_policy isFalse) 37 | name = "tf-trail-foobar" 38 | s3_bucket_name = aws_s3_bucket.foo.id 39 | // 3. AWS CloudTrail logs are not encrypted using Customer Master Keys (CMKs) 40 | // $.resource[*].aws_cloudtrail exists and ($.resource[*].aws_cloudtrail[*].*[*].kms_key_id anyNull or $.resource[*].aws_cloudtrail[*].*[*].kms_key_id anyEmpty) 41 | // #REMOVED TO MAKE RULE MATCH# kms_key_id = "arn:aws:kms:us-west-2:111122223333:key" 42 | s3_key_prefix = "prefix" 43 | include_global_service_events = false 44 | enable_logging = false 45 | } 46 | resource "aws_s3_bucket_public_access_block" "example" { 47 | // 2+. AWS CloudTrail bucket is publicly accessible (high) 48 | bucket = aws_s3_bucket.foo.id 49 | block_public_acls = false 50 | block_public_policy = true 51 | } 52 | 53 | // ??? [Rule Not Matching] 30. AWS VPC allows unauthorized peering 54 | // $.resource[*].aws_vpc_peering_connection[*].*[*].peer_vpc_id does not equal $.resource[*].aws_vpc_peering_connection[*].*[*].vpc_id 55 | resource "aws_vpc_peering_connection" "foo" { 56 | peer_owner_id = "123" 57 | peer_vpc_id = aws_vpc.bar_vpc.id 58 | vpc_id = aws_vpc.foo_vpc.id 59 | } 60 | resource "aws_vpc" "foo_vpc" { 61 | cidr_block = "172.16.0.0/16" 62 | tags = { 63 | Name = "foo-vpc-example" 64 | } 65 | } 66 | resource "aws_vpc" "bar_vpc" { 67 | cidr_block = "172.17.0.0/16" 68 | tags = { 69 | Name = "bar-vpc-example" 70 | } 71 | } 72 | 73 | resource "aws_security_group" "allow_tcp" { 74 | name = "allow_tcp" 75 | description = "Allow TCP inbound traffic" 76 | vpc_id = aws_vpc.foo_vpc.id 77 | // 6. AWS Security Groups allow internet traffic to SSH port (22) 78 | // $.resource[*].aws_security_group exists and ($.resource[*].aws_security_group[*].*[*].ingress[?( @.protocol == 'tcp' && @.from_port<23 && @.to_port>21 )].cidr_blocks[*] contains 0.0.0.0/0 or $.resource[*].aws_security_group[*].*[*].ingress[?( @.protocol == 'tcp' && @.from_port<23 && @.to_port>21 )].ipv6_cidr_blocks[*] contains ::/0) 79 | ingress { 80 | description = "TCP from VPC" 81 | from_port = 22 82 | to_port = 22 83 | protocol = "tcp" 84 | cidr_blocks = [ 85 | "0.0.0.0/0"] 86 | } 87 | // 31. AWS security group allows egress traffic to blocked ports - 21,22,135,137-139,445,69 88 | // $.resource[*].aws_security_group exists and $.resource[*].aws_security_group.*[*].*.egress[?(@.protocol == 'tcp' && @.from_port == '22' && @.to_port == '22')].cidr_blocks[*] == 0.0.0.0/0 or $.resource[*].aws_security_group.*[*].*.egress[?(@.protocol == 'tcp' && @.from_port == '22' && @.to_port == '22')].ipv6_cidr_blocks[*] == ::/0 or $.resource[*].aws_security_group.*[*].*.egress[?(@.protocol == 'tcp' && @.from_port == '21' && @.to_port == '21')].cidr_blocks[*] == 0.0.0.0/0 or $.resource[*].aws_security_group.*[*].*.egress[?(@.protocol == 'tcp' && @.from_port == '21' && @.to_port == '21')].ipv6_cidr_blocks[*] == ::/0 or $.resource[*].aws_security_group.*[*].*.egress[?(@.protocol == 'tcp' && @.from_port == '445' && @.to_port == '445')].cidr_blocks[*] == 0.0.0.0/0 or $.resource[*].aws_security_group.*[*].*.egress[?(@.protocol == 'tcp' && @.from_port == '445' && @.to_port == '445')].ipv6_cidr_blocks[*] == ::/0 or $.resource[*].aws_security_group.*[*].*.egress[?(@.protocol == 'udp' && @.from_port == '135' && @.to_port == '135')].cidr_blocks[*] == 0.0.0.0/0 or $.resource[*].aws_security_group.*[*].*.egress[?(@.protocol == 'udp' && @.from_port == '135' && @.to_port == '135')].ipv6_cidr_blocks[*] == ::/0 or $.resource[*].aws_security_group.*[*].*.egress[?(@.protocol == '-1' && @.from_port == '137' && @.to_port == '139')].cidr_blocks[*] == 0.0.0.0/0 or $.resource[*].aws_security_group.*[*].*.egress[?(@.protocol == '-1' && @.from_port == '137' && @.to_port == '139')].ipv6_cidr_blocks[*] == ::/0 or $.resource[*].aws_security_group.*[*].*.egress[?(@.protocol == 'udp' && @.from_port == '69' && @.to_port == '69')].cidr_blocks[*] == 0.0.0.0/0 or $.resource[*].aws_security_group.*[*].*.egress[?(@.protocol == 'udp' && @.from_port == '69' && @.to_port == '69')].ipv6_cidr_blocks[*] == ::/0 89 | egress { 90 | from_port = 69 91 | to_port = 69 92 | protocol = "udp" 93 | cidr_blocks = [ 94 | "0.0.0.0/0"] 95 | } 96 | } 97 | // 25. AWS Security Groups allow internet traffic from internet to RDP port (3389) 98 | // $.resource[*].aws_security_group exists and ($.resource[*].aws_security_group[*].*[*].ingress[?( @.protocol == 'tcp' && @.from_port<3390 && @.to_port>3388 )].cidr_blocks[*] contains 0.0.0.0/0 or $.resource[*].aws_security_group[*].*[*].ingress[?( @.protocol == 'tcp' && @.from_port<3390 && @.to_port>3388)].ipv6_cidr_blocks[*] contains ::/0) 99 | resource "aws_security_group" "allow_rdp" { 100 | name = "allow_rdp" 101 | description = "Allow RDP inbound traffic" 102 | vpc_id = aws_vpc.bar_vpc.id 103 | ingress { 104 | description = "TCP from VPC" 105 | from_port = 3389 106 | to_port = 3389 107 | protocol = "tcp" 108 | ipv6_cidr_blocks = [ 109 | "::/0"] 110 | } 111 | egress { 112 | from_port = 0 113 | to_port = 0 114 | protocol = "-1" 115 | cidr_blocks = [ 116 | "0.0.0.0/0"] 117 | } 118 | } 119 | // 27. AWS Security Groups with Inbound rule overly permissive to All Traffic 120 | // ($.resource[*].aws_security_group exists and ($.resource[*].aws_security_group.*[*].*.ingress[*].protocol equals -1 and ($.resource[*].aws_security_group.*[*].*.ingress[*].cidr_blocks[*] contains 0.0.0.0/0 or $.resource[*].aws_security_group.*[*].*.ingress[*].ipv6_cidr_blocks[*] contains ::/0))) or ($.resource[*].aws_security_group_rule exists and ($.resource[*].aws_security_group_rule.*[*].*.protocol equals -1 and $.resource[*].aws_security_group_rule.*[*].*.type equals ingress and ($.resource[*].aws_security_group_rule.*[*].*.cidr_blocks[*] contains 0.0.0.0/0 or $.resource[*].aws_security_group_rule.*[*].*.ipv6_cidr_blocks[*] contains ::/0))) 121 | resource "aws_security_group" "allow_all_traffic" { 122 | name = "allow_rdp" 123 | description = "Allow RDP inbound traffic" 124 | vpc_id = aws_vpc.bar_vpc.id 125 | ingress { 126 | description = "TCP from VPC" 127 | from_port = 3389 128 | to_port = 3389 129 | protocol = "-1" 130 | ipv6_cidr_blocks = [ 131 | "::/0"] 132 | } 133 | egress { 134 | from_port = 0 135 | to_port = 0 136 | protocol = "-1" 137 | cidr_blocks = [ 138 | "0.0.0.0/0"] 139 | } 140 | } 141 | // ??? [Not Matching, Dupe of 6?] 32. AWS security groups allow ingress traffic from blocked ports 142 | //$.resource[*].aws_security_group.*[*].*.ingress[?(@.protocol == 'tcp' && @.from_port == '22' && @.to_port == '22')].cidr_blocks[*] == 0.0.0.0/0 or $.resource[*].aws_security_group.*[*].*.ingress[?(@.protocol == 'tcp' && @.from_port == '22' && @.to_port == '22')].ipv6_cidr_blocks[*] == ::/0 or $.resource[*].aws_security_group.*[*].*.ingress[?(@.protocol == 'tcp' && @.from_port == '21' && @.to_port == '21')].cidr_blocks[*] == 0.0.0.0/0 or $.resource[*].aws_security_group.*[*].*.ingress[?(@.protocol == 'tcp' && @.from_port == '21' && @.to_port == '21')].ipv6_cidr_blocks[*] == ::/0 or $.resource[*].aws_security_group.*[*].*.ingress[?(@.protocol == 'tcp' && @.from_port == '5800' && @.to_port == '5800')].cidr_blocks[*] == 0.0.0.0/0 or $.resource[*].aws_security_group.*[*].*.ingress[?(@.protocol == 'tcp' && @.from_port == '5800' && @.to_port == '5800')].ipv6_cidr_blocks[*] == ::/0 or $.resource[*].aws_security_group.*[*].*.ingress[?(@.protocol == 'tcp' && @.from_port == '5900' && @.to_port == '5903')].cidr_blocks[*] == 0.0.0.0/0 or $.resource[*].aws_security_group.*[*].*.ingress[?(@.protocol == 'tcp' && @.from_port == '5900' && @.to_port == '5903')].ipv6_cidr_blocks[*] == ::/0 or $.resource[*].aws_security_group.*[*].*.ingress[?(@.protocol == 'tcp' && @.from_port == '2323' && @.to_port == '2323')].cidr_blocks[*] == 0.0.0.0/0 or $.resource[*].aws_security_group.*[*].*.ingress[?(@.protocol == 'tcp' && @.from_port == '2323' && @.to_port == '2323')].ipv6_cidr_blocks[*] == ::/0 or $.resource[*].aws_security_group.*[*].*.ingress[?(@.protocol == 'tcp' && @.from_port == '23' && @.to_port == '23')].cidr_blocks[*] == 0.0.0.0/0 or $.resource[*].aws_security_group.*[*].*.ingress[?(@.protocol == 'tcp' && @.from_port == '23' && @.to_port == '23')].ipv6_cidr_blocks[*] == ::/0 or $.resource[*].aws_security_group.*[*].*.ingress[?(@.protocol == 'tcp' && @.from_port == '25' && @.to_port == '25')].cidr_blocks[*] == 0.0.0.0/0 or $.resource[*].aws_security_group.*[*].*.ingress[?(@.protocol == 'tcp' && @.from_port == '25' && @.to_port == '25')].ipv6_cidr_blocks[*] == ::/0 or $.resource[*].aws_security_group.*[*].*.ingress[?(@.protocol == 'tcp' && @.from_port == '110' && @.to_port == '110')].cidr_blocks[*] == 0.0.0.0/0 or $.resource[*].aws_security_group.*[*].*.ingress[?(@.protocol == 'tcp' && @.from_port == '110' && @.to_port == '110')].ipv6_cidr_blocks[*] == ::/0 or $.resource[*].aws_security_group.*[*].*.ingress[?(@.protocol == 'tcp' && @.from_port == '143' && @.to_port == '143')].cidr_blocks[*] == 0.0.0.0/0 or $.resource[*].aws_security_group.*[*].*.ingress[?(@.protocol == 'tcp' && @.from_port == '143' && @.to_port == '143')].ipv6_cidr_blocks[*] == ::/0 or $.resource[*].aws_security_group.*[*].*.ingress[?(@.protocol == '-1' && @.from_port == '53' && @.to_port == '53')].cidr_blocks[*] == 0.0.0.0/0 or $.resource[*].aws_security_group.*[*].*.ingress[?(@.protocol == '-1' && @.from_port == '53' && @.to_port == '53')].ipv6_cidr_blocks[*] == ::/0 or $.resource[*].aws_security_group.*[*].*.ingress[?(@.protocol == 'udp' && @.from_port == '135' && @.to_port == '135')].cidr_blocks[*] == 0.0.0.0/0 or $.resource[*].aws_security_group.*[*].*.ingress[?(@.protocol == 'udp' && @.from_port == '135' && @.to_port == '135')].ipv6_cidr_blocks[*] == ::/0 or $.resource[*].aws_security_group.*[*].*.ingress[?(@.protocol == '-1' && @.from_port == '137' && @.to_port == '139')].cidr_blocks[*] == 0.0.0.0/0 or $.resource[*].aws_security_group.*[*].*.ingress[?(@.protocol == '-1' && @.from_port == '137' && @.to_port == '139')].ipv6_cidr_blocks[*] == ::/0 or $.resource[*].aws_security_group.*[*].*.ingress[?(@.protocol == 'udp' && @.from_port == '69' && @.to_port == '69')].cidr_blocks[*] == 0.0.0.0/0 or $.resource[*].aws_security_group.*[*].*.ingress[?(@.protocol == 'udp' && @.from_port == '69' && @.to_port == '69')].ipv6_cidr_blocks[*] == ::/0 143 | resource "aws_security_group" "allow_udp69" { 144 | name = "allow_tcp2" 145 | description = "Allow TCP inbound traffic" 146 | vpc_id = aws_vpc.bar_vpc.id 147 | ingress { 148 | description = "TCP from VPC" 149 | from_port = 69 150 | to_port = 69 151 | protocol = "udp" 152 | cidr_blocks = [ 153 | "0.0.0.0/0"] 154 | } 155 | } 156 | 157 | resource "aws_network_acl" "main" { 158 | vpc_id = aws_vpc.foo_vpc.id 159 | // 28. AWS VPC NACL allows egress traffic from blocked ports 160 | // $.resource[*].aws_network_acl exists and $.resource[*].aws_network_acl.*[*].*.egress[?(@.protocol == 'tcp' && @.from_port == '22' && @.to_port == '22')].action==allow or $.resource[*].aws_network_acl.*[*].*.egress[?(@.protocol == 'tcp' && @.from_port == '21' && @.to_port == '21')].action==allow or $.resource[*].aws_network_acl.*[*].*.egress[?(@.protocol == 'udp' && @.from_port == '135' && @.to_port == '135')].action==allow or $.resource[*].aws_network_acl.*[*].*.egress[?(@.protocol == 'tcp' && @.from_port == '445' && @.to_port == '445')].action==allow or $.resource[*].aws_network_acl.*[*].*.egress[?(@.protocol == '-1' && @.from_port == '137' && @.to_port == '139')].action==allow or $.resource[*].aws_network_acl.*[*].*.egress[?(@.protocol == 'udp' && @.from_port == '69' && @.to_port == '69')].action==allow 161 | egress { 162 | protocol = "tcp" 163 | rule_no = 200 164 | action = "allow" 165 | cidr_block = "10.3.0.0/18" 166 | from_port = 22 167 | to_port = 22 168 | } 169 | // 29. AWS VPC NACL allows traffic from blocked ports 170 | // $.resource[*].aws_network_acl exists and $.resource[*].aws_network_acl.*[*].*.ingress[?(@.protocol == 'tcp' && @.from_port == '22' && @.to_port == '22')].action==allow or $.resource[*].aws_network_acl.*[*].*.ingress[?(@.protocol == 'tcp' && @.from_port == '21' && @.to_port == '21')].action==allow or $.resource[*].aws_network_acl.*[*].*.ingress[?(@.protocol == 'tcp' && @.from_port == '5800' && @.to_port == '5800')].action==allow or $.resource[*].aws_network_acl.*[*].*.ingress[?(@.protocol == 'tcp' && @.from_port == '5900' && @.to_port == '5903')].action==allow or $.resource[*].aws_network_acl.*[*].*.ingress[?(@.protocol == 'tcp' && @.from_port == '2323' && @.to_port == '2323')].action==allow or $.resource[*].aws_network_acl.*[*].*.ingress[?(@.protocol == 'tcp' && @.from_port == '23' && @.to_port == '23')].action==allow or $.resource[*].aws_network_acl.*[*].*.ingress[?(@.protocol == 'tcp' && @.from_port == '25' && @.to_port == '25')].action==allow or $.resource[*].aws_network_acl.*[*].*.ingress[?(@.protocol == 'tcp' && @.from_port == '110' && @.to_port == '110')].action==allow or $.resource[*].aws_network_acl.*[*].*.ingress[?(@.protocol == 'tcp' && @.from_port == '143' && @.to_port == '143')].action==allow or $.resource[*].aws_network_acl.*[*].*.ingress[?(@.protocol == '-1' && @.from_port == '53' && @.to_port == '53')].action==allow or $.resource[*].aws_network_acl.*[*].*.ingress[?(@.protocol == 'udp' && @.from_port == '135' && @.to_port == '135')].action==allow or $.resource[*].aws_network_acl.*[*].*.ingress[?(@.protocol == '-1' && @.from_port == '137' && @.to_port == '139')].action==allow or $.resource[*].aws_network_acl.*[*].*.ingress[?(@.protocol == 'udp' && @.from_port == '69' && @.to_port == '69')].action==allow 171 | ingress { 172 | protocol = "tcp" 173 | rule_no = 100 174 | action = "allow" 175 | cidr_block = "10.3.0.0/18" 176 | from_port = 22 177 | to_port = 22 178 | } 179 | } 180 | // 21. AWS Redshift does not have require_ssl configured 181 | // $.resource[*].aws_redshift_parameter_group exists and ($.resource[*].aws_redshift_parameter_group[*].*[*].parameter[?(@.name=='require_ssl')] !exists or $.resource[*].aws_redshift_parameter_group[*].*[*].parameter[?(@.name=='require_ssl' && @.value=='false' )] exists) 182 | resource "aws_redshift_parameter_group" "bar" { 183 | name = "parameter-group-test-terraform" 184 | family = "redshift-1.0" 185 | parameter { 186 | name = "require_ssl" 187 | value = "false" 188 | } 189 | } 190 | 191 | resource "aws_db_instance" "default" { 192 | allocated_storage = 20 193 | storage_type = "gp2" 194 | engine = "mysql" 195 | engine_version = "5.7" 196 | instance_class = "db.t2.micro" 197 | name = "mydb" 198 | username = "foo" 199 | password = "foobarbaz" 200 | parameter_group_name = "default.mysql5.7" 201 | // 20. AWS RDS snapshots are accessible to public (high) 202 | // $.resource[*].aws_db_instance exists and ($.resource[*].aws_db_instance[*].*[*].publicly_accessible !exists or $.resource[*].aws_db_instance[*].*[*].publicly_accessible anyTrue) 203 | publicly_accessible = true 204 | } 205 | // 19. AWS RDS event subscription disabled for DB security groups (medium) 206 | // $.resource[*].aws_db_instance exists and ( $.resource[*].aws_db_event_subscription !exists or $.resource[*].aws_db_event_subscription[*].*[?(@.source_type=='db-security-group')] anyNull or not $.resource[*].aws_db_event_subscription[*].*[?(@.source_type=='db-security-group')].enabled anyNull or $.resource[*].aws_db_event_subscription[*].*[?(@.source_type=='db-security-group')].enabled anyTrue ) 207 | resource "aws_sns_topic" "default" { 208 | name = "rds-events" 209 | } 210 | resource "aws_db_event_subscription" "default" { 211 | name = "rds-event-sub" 212 | sns_topic = aws_sns_topic.default.arn 213 | source_type = "db-security-group" 214 | source_ids = [ 215 | aws_db_instance.default.id] 216 | event_categories = [ 217 | "availability", 218 | "deletion", 219 | "failover", 220 | "failure", 221 | "low storage", 222 | "maintenance", 223 | "notification", 224 | "read replica", 225 | "recovery", 226 | "restoration", 227 | ] 228 | enabled = false 229 | } 230 | 231 | // 4. AWS Customer Master Key (CMK) rotation is not enabled (medium) 232 | // $.resource[*].aws_kms_key exists and ( $.resource[*].aws_kms_key[*].*[*].enable_key_rotation anyFalse or $.resource[*].aws_kms_key[*].*[*].enable_key_rotation anyNull) 233 | resource "aws_kms_key" "a" { 234 | description = "KMS key 1" 235 | enable_key_rotation = false 236 | } 237 | 238 | // 5. AWS Default Security Group does not restrict all traffic (high) 239 | // $.resource[*].aws_default_security_group exists and ($.resource[*].aws_default_security_group[*].*[*].ingress[*].cidr_blocks[*] contains 0.0.0.0/0 or $.resource[*].aws_default_security_group[*].*[*].ingress[*].ipv6_cidr_blocks[*] contains ::/0 or $.resource[*].aws_default_security_group[*].*[*].egress[*].cidr_blocks[*] contains 0.0.0.0/0 or $.resource[*].aws_default_security_group[*].*[*].egress[*].ipv6_cidr_blocks[*] contains ::/0) 240 | resource "aws_vpc" "mainvpc" { 241 | cidr_block = "10.1.0.0/16" 242 | } 243 | resource "aws_default_security_group" "default" { 244 | vpc_id = aws_vpc.mainvpc.id 245 | 246 | ingress { 247 | protocol = -1 248 | self = true 249 | from_port = 0 250 | to_port = 0 251 | cidr_blocks = [ 252 | "0.0.0.0/0"] 253 | } 254 | } 255 | 256 | 257 | data "aws_iam_role" "ecs_task_execution_role" { 258 | name = "ecsTaskExecutionRole" 259 | } 260 | resource "aws_ecs_task_definition" "github-backup" { 261 | family = "github-backup" 262 | requires_compatibilities = [ 263 | "FARGATE"] 264 | network_mode = "awsvpc" 265 | cpu = 1 266 | memory = 128 267 | task_role_arn = "${data.aws_iam_role.ecs_task_execution_role.arn}" 268 | // 7. AWS ECS/ Fargate task definition execution IAM Role not found (medium) 269 | // $.resource[*].aws_ecs_task_definition exists and $.resource[*].aws_ecs_task_definition[*].*[*].container_definitions exists and ($.resource[*].aws_ecs_task_definition[*].*[*].execution_role_arn anyNull or $.resource[*].aws_ecs_task_definition[*].*[*].execution_role_arn anyEmpty) 270 | execution_role_arn = "" 271 | // 8. AWS ECS/ Fargate task definition root user found 272 | // $.resource[*].aws_ecs_task_definition[*].*[*].container_definitions[?(@.user=='root')] exists 273 | container_definitions = <90 )] is not empty 341 | max_password_age = 91 342 | // 12. AWS IAM password policy does not have a minimum of 14 characters (medium) 343 | // $.resource[*].aws_iam_account_password_policy[*].*[?( @.minimum_password_length<14 )] is not empty 344 | minimum_password_length = 8 345 | // 13. AWS IAM password policy does not have a lowercase character (medium) 346 | // $.resource[*].aws_iam_account_password_policy[*].*[*] 347 | require_lowercase_characters = false 348 | // 14. AWS IAM password policy does not have a number (medium) 349 | // $.resource[*].aws_iam_account_password_policy[*].*[*].require_numbers anyFalse 350 | require_numbers = false 351 | // 15. AWS IAM password policy does not have a symbol (medium) 352 | //$.resource[*].aws_iam_account_password_policy[*].*[*].require_symbols anyFalse 353 | require_symbols = false 354 | // 16. AWS IAM password policy does not have a uppercase character (medium) 355 | // $.resource[*].aws_iam_account_password_policy[*].*[*].require_uppercase_characters anyFalse 356 | require_uppercase_characters = false 357 | allow_users_to_change_password = true 358 | } 359 | 360 | // 17. AWS IAM policy attached to users (low) 361 | // $.resource[*].aws_iam_policy_attachment[*].*[*].users exists and $.resource[*].aws_iam_policy_attachment[*].*[*].users[*] is not empty 362 | resource "aws_iam_policy_attachment" "test-attach" { 363 | name = "test-attachment" 364 | users = [ 365 | "test-user"] 366 | roles = [ 367 | "test-role"] 368 | groups = [ 369 | "test-group"] 370 | policy_arn = "arn:aws:kms:us-west-2:111122223333:key" 371 | } 372 | 373 | // 18. AWS EKS unsupported Master node version (high) 374 | // $.resource[*].aws_eks_cluster[*].*[*].version anyStartWith 1.9. 375 | resource "aws_eks_cluster" "example" { 376 | name = "example" 377 | role_arn = data.aws_iam_role.ecs_task_execution_role.arn 378 | vpc_config { 379 | subnet_ids = [ 380 | data.aws_subnet_ids.example.id] 381 | } 382 | version = "1.9.9" 383 | } -------------------------------------------------------------------------------- /TF/tf12_fixed_issues/tf12_fixed_issues.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.12.0" 3 | } 4 | 5 | provider "aws" { 6 | region = "us-east-1" 7 | } 8 | 9 | resource "aws_s3_bucket" "foo" { 10 | bucket = "my-tf-log-bucket" 11 | acl = "private" 12 | versioning { 13 | enabled = true 14 | } 15 | logging { 16 | target_bucket = "logging_bucket" 17 | target_prefix = "log/" 18 | } 19 | } -------------------------------------------------------------------------------- /TF/tf12_gcp_all_issues/gcp_all_issues.tf: -------------------------------------------------------------------------------- 1 | resource "google_container_cluster" "primary" { 2 | provider = google 3 | name = "my-gke-cluster" 4 | location = "us-central1" 5 | initial_node_count = 1 6 | // GCP Kubernetes Engine Clusters have Legacy Authorization enabled 7 | // $.resource[*].google_container_cluster.*.*[*].enable_legacy_abac anyTrue 8 | enable_legacy_abac = true 9 | 10 | //??? GCP Kubernetes Engine Clusters have Master authorized networks disabled 11 | //$.resource[*].google_container_cluster[*].*.*.master_authorized_networks_config anyNull 12 | master_authorized_networks_config { 13 | } 14 | //GCP Kubernetes Engine Clusters not configured with private cluster 15 | //$.resource[*].google_container_cluster exists and ($.resource[*].google_container_cluster.*[*].*.private_cluster_config anyNull or $.resource[*].google_container_cluster.*[*].*.private_cluster_config[*].enable_private_nodes anyNull or $.resource[*].google_container_cluster.*[*].*.private_cluster_config[*].enable_private_nodes anyFalse) 16 | private_cluster_config { 17 | enable_private_endpoint = false 18 | enable_private_nodes = false 19 | } 20 | 21 | network_policy { 22 | enabled = true 23 | provider = "CALICO" 24 | } 25 | // GCP Kubernetes Engine Clusters have Network policy disableds 26 | // $.resource[*].google_container_cluster exists and ($.resource[*].google_container_cluster.*[*].*.network_policy anyNull or $.resource[*].google_container_cluster.*[*].*.addons_config[*].network_policy_config anyNull or $.resource[*].google_container_cluster.*[*].*.addons_config[*].network_policy_config[*].disabled anyNull or $.resource[*].google_container_cluster.*[*].*.addons_config[*].network_policy_config[*].disabled anyTrue) 27 | addons_config { 28 | network_policy_config { 29 | disabled = true 30 | } 31 | // GCP Kubernetes cluster istioConfig not enabled 32 | // $.resource[*].google_container_cluster exists and ($.resource[*].google_container_cluster.*[*].*.addons_config anyNull or $.resource[*].google_container_cluster.*[*].*.addons_config[*].istio_config anyNull or $.resource[*].google_container_cluster.*[*].*.addons_config[*].istio_config[*] anyNull or $.resource[*].google_container_cluster.*[*].*.addons_config[*].istio_config[*].disabled anyNull or $.resource[*].google_container_cluster.*[*].*.addons_config[*].istio_config[*].disabled anyTrue) 33 | // istio_config { 34 | // disabled = true 35 | // } 36 | // GCP Kubernetes Engine Clusters have HTTP load balancing disabled 37 | // $.resource[*].google_container_cluster exists and ($.resource[*].google_container_cluster.*[*].*.addons_config[*].http_load_balancing[*].disabled anyTrue) 38 | http_load_balancing { 39 | disabled = true 40 | } 41 | 42 | // GCP Kubernetes Engine Clusters web UI/Dashboard is set to Enabled 43 | // $.resource[*].google_container_cluster exists and $.resource[*].google_container_cluster.*[*].*.addons_config[*].kubernetes_dashboard[*].disabled anyFalse 44 | // kubernetes_dashboard { 45 | // disabled = false 46 | // } 47 | } 48 | 49 | //GCP Kubernetes cluster Application-layer Secrets not encrypteds 50 | //$.resource[*].google_container_cluster exists and ($.resource[*].google_container_cluster[*].*[*].database_encryption anyNull or $.resource[*].google_container_cluster[*].*[*].database_encryption[*].state any equal DECRYPTED) 51 | database_encryption { 52 | state = "DECRYPTED" 53 | key_name = "key" 54 | } 55 | 56 | // GCP Kubernetes Engine Clusters have Alias IP disabled 57 | // $.resource[*].google_container_cluster exists and $.resource[*].google_container_cluster[*].*.*.ip_allocation_policy does not exist 58 | // ip_allocation_policy { 59 | // cluster_ipv4_cidr_block = "10.32.0.0/14" 60 | // services_ipv4_cidr_block = "10.0.0.0/20" 61 | // } 62 | 63 | node_config { 64 | // GCP Kubernetes Engine Cluster Nodes have default Service account for Project access 65 | // $.resource[*].google_container_cluster[*].*[*].node_config anyNull or $.resource[*].google_container_cluster[*].*[*].node_config[*].service_account anyNull 66 | // service_account = "default" 67 | preemptible = true 68 | machine_type = "e2-medium" 69 | 70 | metadata = { 71 | disable-legacy-endpoints = "true" 72 | } 73 | 74 | oauth_scopes = [ 75 | "https://www.googleapis.com/auth/logging.write", 76 | "https://www.googleapis.com/auth/monitoring", 77 | ] 78 | } 79 | 80 | // GCP Kubernetes Engine Clusters have pod security policy disabled 81 | // $.resource[*].google_container_cluster.*[*].*.pod_security_policy_config anyNull or $.resource[*].google_container_cluster.*[*].*.pod_security_policy_config.enabled anyFalse 82 | // pod_security_policy_config { 83 | // enabled = false 84 | // } 85 | 86 | master_auth { 87 | //GCP Kubernetes Engine Clusters Basic Authentication is set to Enabled 88 | //$.resource.*.google_container_cluster.*.*.*.master_auth exists and not ($.resource.*.google_container_cluster.*.*.*.master_auth.*.password is empty and $.resource.*.google_container_cluster.*.*.*.master_auth.*.username is empty) 89 | username = "abc" 90 | password = "" 91 | 92 | //GCP Kubernetes Engine Clusters Client Certificate is set to Disabled 93 | //$.resource[*].google_container_cluster[*].*.*.master_auth[*].client_certificate_config[*].issue_client_certificate anyTrue 94 | client_certificate_config { 95 | issue_client_certificate = true 96 | } 97 | } 98 | } 99 | 100 | 101 | resource "google_container_node_pool" "primary_preemptible_nodes" { 102 | name = "my-node-pool" 103 | location = "us-central1" 104 | cluster = google_container_cluster.primary.name 105 | node_count = 1 106 | 107 | node_config { 108 | preemptible = true 109 | machine_type = "e2-medium" 110 | //GCP Kubernetes Engine Clusters not using Container-Optimized OS for Node image 111 | //$.resource[*].google_container_node_pool exists and ($.resource[*].google_container_node_pool.*[*].*.node_config anyNull or $.resource[*].google_container_node_pool.*[*].*.node_config[*].image_type anyNull or not $.resource[*].google_container_node_pool.*[*].*.node_config[*].image_type allStartWith cos ) 112 | image_type = "2cos" 113 | 114 | oauth_scopes = [ 115 | "https://www.googleapis.com/auth/logging.write", 116 | "https://www.googleapis.com/auth/monitoring", 117 | ] 118 | } 119 | } 120 | 121 | resource "google_storage_bucket" "static-site" { 122 | name = "image-store.com" 123 | location = "EU" 124 | force_destroy = true 125 | 126 | uniform_bucket_level_access = true 127 | //GCP Storage log buckets have object versioning disabled 128 | //$.resource[*].google_storage_bucket exists and ($.resource[*].google_storage_bucket.*[*].*.versioning anyNull or $.resource[*].google_storage_bucket.*[*].*.versioning[*].enabled anyNull or $.resource[*].google_storage_bucket.*[*].*.versioning[*].enabled anyFalse) 129 | versioning { 130 | enabled = false 131 | } 132 | // Storage Bucket does not have Access and Storage Logging enabled 133 | //$.resource[*].google_storage_bucket exists and ($.resource[*].google_storage_bucket.*[*].*.logging anyNull or $.resource[*].google_storage_bucket.*[*].*.logging[*].log_bucket anyEmpty) 134 | // logging { 135 | // log_bucket = "" 136 | // } 137 | } 138 | 139 | //GCP Storage buckets are publicly accessible to all authenticated users 140 | //$.resource[*].google_storage_bucket_access_control[*].*[*].entity contains allUsers 141 | resource "google_storage_bucket_access_control" "public_rule" { 142 | bucket = google_storage_bucket.static-site.name 143 | role = "READER" 144 | entity = "allUsers" 145 | } 146 | 147 | resource "google_storage_bucket_access_control" "public_rule2" { 148 | bucket = google_storage_bucket.bucket.name 149 | role = "READER" 150 | entity = "allUsers" 151 | } 152 | 153 | resource "google_storage_bucket" "bucket" { 154 | name = "static-content-bucket" 155 | } 156 | 157 | //SQL Instances do not have SSL configured 158 | //$.resource[*].google_sql_database_instance exists and $.resource[*].google_sql_ssl_cert !exists 159 | //resource "google_sql_ssl_cert" "client_cert" { 160 | // common_name = "client-name" 161 | // instance = google_sql_database_instance.master.name 162 | //} 163 | 164 | //SQL Instances with network authorization exposing them to the Internet 165 | //$.resource[*].google_sql_database_instance[*].*[*].settings[*].ip_configuration[*].authorized_networks[*].value anyEqual 0.0.0.0/0 or $.resource[*].google_sql_database_instance[*].*[*].settings[*].ip_configuration[*].authorized_networks[*].value anyEqual ::/0 166 | resource "google_sql_database_instance" "master" { 167 | name = "master-instance" 168 | database_version = "POSTGRES_11" 169 | region = "us-central1" 170 | 171 | settings { 172 | # Second-generation instance tiers are based on the machine 173 | # type. See argument reference below. 174 | tier = "db-f1-micro" 175 | } 176 | } 177 | resource "google_compute_instance" "apps" { 178 | count = 8 179 | name = "apps-${count.index + 1}" 180 | machine_type = "f1-micro" 181 | 182 | boot_disk { 183 | initialize_params { 184 | image = "ubuntu-os-cloud/ubuntu-1804-lts" 185 | } 186 | } 187 | 188 | network_interface { 189 | network = "default" 190 | 191 | access_config { 192 | // Ephemeral IP 193 | } 194 | } 195 | } 196 | 197 | resource "random_id" "db_name_suffix" { 198 | byte_length = 4 199 | } 200 | 201 | locals { 202 | onprem = [ 203 | "0.0.0.0/0", 204 | "::/0"] 205 | } 206 | 207 | resource "google_sql_database_instance" "postgres" { 208 | name = "postgres-instance-${random_id.db_name_suffix.hex}" 209 | database_version = "POSTGRES_11" 210 | 211 | settings { 212 | tier = "db-f1-micro" 213 | 214 | ip_configuration { 215 | //SQL Instances with network authorization exposing them to the Internet 216 | // $.resource[*].google_sql_database_instance[*].*[*].settings[*].ip_configuration[*].authorized_networks[*].value anyEqual 0.0.0.0/0 or $.resource[*].google_sql_database_instance[*].*[*].settings[*].ip_configuration[*].authorized_networks[*].value anyEqual ::/0 217 | dynamic "authorized_networks" { 218 | for_each = google_compute_instance.apps 219 | iterator = apps 220 | 221 | content { 222 | name = apps.value.name 223 | value = apps.value.network_interface.0.access_config.0.nat_ip 224 | } 225 | } 226 | 227 | dynamic "authorized_networks" { 228 | for_each = local.onprem 229 | iterator = onprem 230 | 231 | content { 232 | name = "onprem-${onprem.key}" 233 | value = onprem.value 234 | } 235 | } 236 | } 237 | } 238 | } 239 | 240 | //GCP User managed service accounts have user managed service account keys 241 | //$.resource[*].google_service_account_key[*].*[*].service_account_id contains google_service_account or $.resource[*].google_service_account_key[*].*[*].service_account_id any end with iam.gserviceaccount.com 242 | resource "google_service_account_key" "mykey" { 243 | service_account_id = "iam.gserviceaccount.com" 244 | public_key_type = "TYPE_X509_PEM_FILE" 245 | } 246 | 247 | //GCP VM disks not encrypted with Customer-Supplied Encryption Keys (CSEK) 248 | //$.resource[*].google_compute_disk exists and $.resource[*].google_compute_disk.*.[*].*.disk_encrypt_key does not exist 249 | resource "google_compute_disk" "default" { 250 | name = "test-disk" 251 | type = "pd-ssd" 252 | zone = "us-central1-a" 253 | image = "debian-8-jessie-v20170523" 254 | labels = { 255 | environment = "dev" 256 | } 257 | physical_block_size_bytes = 4096 258 | } 259 | 260 | //GCP VM instances have IP forwarding enabled 261 | //$.resource[*].google_compute_instance_template[*].*.[*].can_ip_forward anyTrue 262 | resource "google_compute_instance_template" "instance_template" { 263 | name_prefix = "instance-template-" 264 | machine_type = "n1-standard-1" 265 | region = "us-central1" 266 | 267 | can_ip_forward = true 268 | 269 | // boot disk 270 | disk { 271 | # ... 272 | } 273 | 274 | // networking 275 | network_interface { 276 | # ... 277 | } 278 | 279 | lifecycle { 280 | create_before_destroy = true 281 | } 282 | } 283 | 284 | //GCP VPC Network subnets have Private Google access disabled 285 | //$.resource[*].google_compute_subnetwork[*].*[*].private_ip_google_access anyNull or $.resource[*].google_compute_subnetwork[*].*[*].private_ip_google_access anyFalse 286 | resource "google_compute_subnetwork" "network-with-private-secondary-ip-ranges" { 287 | name = "test-subnetwork" 288 | ip_cidr_range = "10.2.0.0/16" 289 | region = "us-central1" 290 | network = google_compute_network.custom-test.id 291 | private_ip_google_access = false 292 | secondary_ip_range { 293 | range_name = "tf-test-secondary-range-update1" 294 | ip_cidr_range = "192.168.10.0/24" 295 | } 296 | } 297 | resource "google_compute_network" "custom-test" { 298 | name = "test-network" 299 | auto_create_subnetworks = false 300 | } 301 | 302 | //GCP Kubernetes Engine Clusters using the default network 303 | //$.resource[*].google_project[*].*[*].auto_create_network anyTrue or $.resource[*].google_project[*].*[*].auto_create_network anyNull 304 | resource "google_project" "my_project" { 305 | name = "My Project" 306 | project_id = "your-project-id" 307 | org_id = "1234567" 308 | auto_create_network = true 309 | } 310 | 311 | //GCP Projects have OS Login disabled 312 | //$.resource[*].google_compute_project_metadata_item.[*].[*].[*].key exists and $.resource[*].google_compute_project_metadata_item.[*].[*].[*].key == enable-oslogin and $.resource[*].google_compute_project_metadata_item.[*].[*].[*].value exists and $.resource[*].google_compute_project_metadata_item.[*].[*].[*].value == FALSE 313 | resource "google_compute_project_metadata_item" "default" { 314 | key = "enable-oslogin" 315 | value = "FALSE" 316 | } 317 | 318 | //GCP IAM Service account has admin privileges 319 | //GCP IAM user with service account privileges 320 | //GCP IAM user have overly permissive Cloud KMS roles 321 | data "google_iam_policy" "admin" { 322 | binding { 323 | role = "roles/editor" 324 | members = [ 325 | "serviceAccount:your-custom-sa@your-project.iam.gserviceaccount.com", 326 | ] 327 | } 328 | binding { 329 | role = "roles/iam.serviceAccountUser" 330 | members = [ 331 | "user:abc@gmail.com", 332 | ] 333 | } 334 | binding { 335 | role = "roles/cloudkms.admin" 336 | members = [ 337 | "user:abc@gmail.com", 338 | ] 339 | } 340 | } 341 | resource "google_project_iam_member" "sql_client" { 342 | role = "roles/editor" 343 | member = "serviceAccount:your-custom-sa@your-project.iam.gserviceaccount.com" 344 | } 345 | resource "google_project_iam_member" "sql_client2" { 346 | role = "roles/iam.serviceAccountUser" 347 | member = "user:abc@gmail.com" 348 | } 349 | resource "google_project_iam_member" "sql_client3" { 350 | role = "roles/cloudkms.admin" 351 | member = "user:abc@gmail.com" 352 | } -------------------------------------------------------------------------------- /TF/tf12_multiple-modules/examples/complete/README.md: -------------------------------------------------------------------------------- 1 | # Complete S3 bucket with most of supported features enabled 2 | 3 | Configuration in this directory creates S3 bucket which demos such capabilities: 4 | - static web-site hosting 5 | - access logging (for S3 and ELB) 6 | - versioning 7 | - CORS 8 | - lifecycle rules 9 | - server-side encryption 10 | - object locking 11 | 12 | Please check [S3 replication example](https://github.com/terraform-aws-modules/terraform-aws-s3-bucket/tree/master/examples/complete) to see Cross-Region Replication (CRR) supported by this module. 13 | 14 | ## Usage 15 | 16 | To run this example you need to execute: 17 | 18 | ```bash 19 | $ terraform init 20 | $ terraform plan 21 | $ terraform apply 22 | ``` 23 | 24 | Note that this example may create resources which cost money. Run `terraform destroy` when you don't need these resources. 25 | 26 | 27 | ## Outputs 28 | 29 | | Name | Description | 30 | |------|-------------| 31 | | this\_s3\_bucket\_arn | The ARN of the bucket. Will be of format arn:aws:s3:::bucketname. | 32 | | this\_s3\_bucket\_bucket\_domain\_name | The bucket domain name. Will be of format bucketname.s3.amazonaws.com. | 33 | | this\_s3\_bucket\_bucket\_regional\_domain\_name | The bucket region-specific domain name. The bucket domain name including the region name, please refer here for format. Note: The AWS CloudFront allows specifying S3 region-specific endpoint when creating S3 origin, it will prevent redirect issues from CloudFront to S3 Origin URL. | 34 | | this\_s3\_bucket\_hosted\_zone\_id | The Route 53 Hosted Zone ID for this bucket's region. | 35 | | this\_s3\_bucket\_id | The name of the bucket. | 36 | | this\_s3\_bucket\_region | The AWS region this bucket resides in. | 37 | | this\_s3\_bucket\_website\_domain | The domain of the website endpoint, if the bucket is configured with a website. If not, this will be an empty string. This is used to create Route 53 alias records. | 38 | | this\_s3\_bucket\_website\_endpoint | The website endpoint, if the bucket is configured with a website. If not, this will be an empty string. | 39 | 40 | 41 | -------------------------------------------------------------------------------- /TF/tf12_multiple-modules/examples/complete/main.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | bucket_name = "s3-bucket-${random_pet.this.id}" 3 | } 4 | 5 | resource "random_pet" "this" { 6 | length = 2 7 | } 8 | 9 | resource "aws_kms_key" "objects" { 10 | description = "KMS key is used to encrypt bucket objects" 11 | deletion_window_in_days = 7 12 | } 13 | 14 | resource "aws_iam_role" "this" { 15 | assume_role_policy = < 20 | ## Outputs 21 | 22 | | Name | Description | 23 | |------|-------------| 24 | | this\_s3\_bucket\_arn | The ARN of the bucket. Will be of format arn:aws:s3:::bucketname. | 25 | | this\_s3\_bucket\_bucket\_domain\_name | The bucket domain name. Will be of format bucketname.s3.amazonaws.com. | 26 | | this\_s3\_bucket\_bucket\_regional\_domain\_name | The bucket region-specific domain name. The bucket domain name including the region name, please refer here for format. Note: The AWS CloudFront allows specifying S3 region-specific endpoint when creating S3 origin, it will prevent redirect issues from CloudFront to S3 Origin URL. | 27 | | this\_s3\_bucket\_hosted\_zone\_id | The Route 53 Hosted Zone ID for this bucket's region. | 28 | | this\_s3\_bucket\_id | The name of the bucket. | 29 | | this\_s3\_bucket\_region | The AWS region this bucket resides in. | 30 | | this\_s3\_bucket\_website\_domain | The domain of the website endpoint, if the bucket is configured with a website. If not, this will be an empty string. This is used to create Route 53 alias records. | 31 | | this\_s3\_bucket\_website\_endpoint | The website endpoint, if the bucket is configured with a website. If not, this will be an empty string. | 32 | 33 | 34 | -------------------------------------------------------------------------------- /TF/tf12_multiple-modules/examples/s3-replication/iam.tf: -------------------------------------------------------------------------------- 1 | resource "aws_iam_role" "replication" { 2 | name = "s3-bucket-replication-${random_pet.this.id}" 3 | 4 | assume_role_policy = <