--- policy: /ce/ca/aws/ecs/service-public-ip-auto-assignment logic: /ce/ca/aws/ecs/service-public-ip-auto-assignment/prod.logic.yaml executionTime: 2026-06-06T12:02:49.425219783Z generationMs: 50 executionMs: 791 rows: - id: test1 match: true status: expected: DISAPPEARED actual: DISAPPEARED conditionIndex: expected: 99 actual: 99 conditionText: expected: isDisappeared(CA10__disappearanceTime__c) actual: isDisappeared(CA10__disappearanceTime__c) runtimeError: {} - id: test2 match: true status: expected: INCOMPLIANT actual: INCOMPLIANT conditionIndex: expected: 299 actual: 299 conditionText: expected: extract('CA10__assignPublicIp__c') == 'Enabled' actual: extract('CA10__assignPublicIp__c') == 'Enabled' runtimeError: {} - id: test3 match: true status: expected: COMPLIANT actual: COMPLIANT conditionIndex: expected: 399 actual: 399 conditionText: expected: extract('CA10__assignPublicIp__c') == 'Disabled' actual: extract('CA10__assignPublicIp__c') == 'Disabled' runtimeError: {} - id: test4 match: true status: expected: INAPPLICABLE actual: INAPPLICABLE conditionIndex: expected: 199 actual: 199 conditionText: expected: extract('CA10__status__c') != 'ACTIVE' actual: extract('CA10__status__c') != 'ACTIVE' runtimeError: {} usedFiles: - path: /ce/ca/aws/ecs/service-public-ip-auto-assignment/policy.yaml md5Hash: AFC38625B8FB28748AA543C94CE159E7 content: | --- names: full: "AWS ECS Service automatically assigns public IP addresses" contextual: "Service automatically assigns public IP addresses" description: > Ensure that Amazon ECS services do not automatically assign public IP addresses to tasks. Assigning public IPs to tasks makes them directly accessible from the internet, increasing the attack surface. type: "COMPLIANCE_POLICY" categories: - "SECURITY" frameworkMappings: - "/frameworks/cloudaware/resource-security/network-exposure" - "/frameworks/aws-fsbp-v1.0.0/ecs/02" similarPolicies: awsSecurityHub: - name: "[ECS.2] ECS services should not have public IP addresses assigned to them automatically" url: "https://docs.aws.amazon.com/securityhub/latest/userguide/ecs-controls.html#ecs-2" - path: /ce/ca/aws/ecs/service-public-ip-auto-assignment/prod.logic.yaml md5Hash: 7C5EC3BC87DD9770A6FE050E8AF37A19 content: | --- inputType: "CA10__CaAwsEcsService__c" testData: - file: "test-data.json" importExtracts: - file: "/types/CA10__CaAwsEcsService__c/object.extracts.yaml" conditions: - status: "INAPPLICABLE" currentStateMessage: "The service is not active." check: NOT_EQUAL: left: EXTRACT: "CA10__status__c" right: TEXT: "ACTIVE" - status: "INCOMPLIANT" currentStateMessage: "The ECS service is configured to automatically assign public IP addresses." remediationMessage: "Update the service network configuration to disable auto-assign public IP." check: IS_EQUAL: left: EXTRACT: "CA10__assignPublicIp__c" right: TEXT: "Enabled" - status: "COMPLIANT" currentStateMessage: "The ECS service is configured not to assign public IP addresses." check: IS_EQUAL: left: EXTRACT: "CA10__assignPublicIp__c" right: TEXT: "Disabled" otherwise: status: "UNDETERMINED" currentStateMessage: "Unexpected values in the field." - path: /ce/ca/aws/ecs/service-public-ip-auto-assignment/test-data.json md5Hash: CB1855150DDA59389504020AF251CD34 content: |- [ { "CA10__assignPublicIp__c": "Disabled", "expectedResult": { "runtimeError": null, "conditionText": "isDisappeared(CA10__disappearanceTime__c)", "conditionIndex": 99, "status": "DISAPPEARED" }, "context": { "snapshotTime": "2025-12-12T04:42:59Z" }, "Id": "test1", "CA10__disappearanceTime__c": "2025-12-05T02:07:04Z", "CA10__status__c": "ACTIVE" }, { "CA10__assignPublicIp__c": "Enabled", "expectedResult": { "runtimeError": null, "conditionText": "extract('CA10__assignPublicIp__c') == 'Enabled'", "conditionIndex": 299, "status": "INCOMPLIANT" }, "context": { "snapshotTime": "2025-12-12T04:42:59Z" }, "Id": "test2", "CA10__disappearanceTime__c": null, "CA10__status__c": "ACTIVE" }, { "CA10__assignPublicIp__c": "Disabled", "expectedResult": { "runtimeError": null, "conditionText": "extract('CA10__assignPublicIp__c') == 'Disabled'", "conditionIndex": 399, "status": "COMPLIANT" }, "context": { "snapshotTime": "2025-12-12T04:42:59Z" }, "Id": "test3", "CA10__disappearanceTime__c": null, "CA10__status__c": "ACTIVE" }, { "CA10__assignPublicIp__c": "Disabled", "expectedResult": { "runtimeError": null, "conditionText": "extract('CA10__status__c') != 'ACTIVE'", "conditionIndex": 199, "status": "INAPPLICABLE" }, "context": { "snapshotTime": "2025-12-12T04:42:59Z" }, "Id": "test4", "CA10__disappearanceTime__c": null, "CA10__status__c": "INACTIVE" } ] - path: /types/CA10__CaAwsEcsService__c/object.extracts.yaml md5Hash: DE9B8176332CECD4A8C53207B8DA95F0 content: | --- extracts: # Values: Enabled | Disabled. Not nullable. - name: "CA10__assignPublicIp__c" value: FIELD: path: "CA10__assignPublicIp__c" undeterminedIf: noAccessDelegate: path: "CA10__assignPublicIp__c" currentStateMessage: "Service Assign Public IP config cannot be empty. Possible permission issue with ecs:DescribeServices" # Values: ACTIVE | DRAINING | INACTIVE. Not nullable. - name: "CA10__status__c" value: FIELD: path: "CA10__status__c" undeterminedIf: noAccessDelegate: path: "CA10__status__c" currentStateMessage: "Service status cannot be empty. Possible permission issue with ecs:DescribeServices" # Values: EC2 | FARGATE | EXTERNAL | MANAGED_INSTANCES # Nullable - name: "CA10__launchType__c" value: FIELD: path: "CA10__launchType__c" # Nullable. - name: "CA10__platformVersion__c" value: FIELD: path: "CA10__platformVersion__c" script: |- CREATE TEMP FUNCTION mock_ExpectedResult() RETURNS ARRAY >> DETERMINISTIC LANGUAGE js AS r""" return [ { "Id" : "test1", "expectedResult" : { "runtimeError" : null, "conditionText" : "isDisappeared(CA10__disappearanceTime__c)", "conditionIndex" : 99, "status" : "DISAPPEARED" } }, { "Id" : "test2", "expectedResult" : { "runtimeError" : null, "conditionText" : "extract('CA10__assignPublicIp__c') == 'Enabled'", "conditionIndex" : 299, "status" : "INCOMPLIANT" } }, { "Id" : "test3", "expectedResult" : { "runtimeError" : null, "conditionText" : "extract('CA10__assignPublicIp__c') == 'Disabled'", "conditionIndex" : 399, "status" : "COMPLIANT" } }, { "Id" : "test4", "expectedResult" : { "runtimeError" : null, "conditionText" : "extract('CA10__status__c') != 'ACTIVE'", "conditionIndex" : 199, "status" : "INAPPLICABLE" } } ]; """; CREATE TEMP FUNCTION mock_CA10__CaAwsEcsService__c() RETURNS ARRAY >> DETERMINISTIC LANGUAGE js AS r""" return [ { "context" : { "snapshotTime" : new Date("2025-12-12T04:42:59Z") }, "CA10__disappearanceTime__c" : new Date("2025-12-05T02:07:04Z"), "CA10__status__c" : "ACTIVE", "CA10__assignPublicIp__c" : "Disabled", "Id" : "test1" }, { "context" : { "snapshotTime" : new Date("2025-12-12T04:42:59Z") }, "CA10__status__c" : "ACTIVE", "CA10__assignPublicIp__c" : "Enabled", "Id" : "test2" }, { "context" : { "snapshotTime" : new Date("2025-12-12T04:42:59Z") }, "CA10__status__c" : "ACTIVE", "CA10__assignPublicIp__c" : "Disabled", "Id" : "test3" }, { "context" : { "snapshotTime" : new Date("2025-12-12T04:42:59Z") }, "CA10__status__c" : "INACTIVE", "CA10__assignPublicIp__c" : "Disabled", "Id" : "test4" } ]; """; CREATE TEMP FUNCTION process_CA10__CaAwsEcsService__c( obj STRUCT< CA10__disappearanceTime__c TIMESTAMP, CA10__status__c STRING, CA10__assignPublicIp__c STRING, Id STRING >, snapshotTime TIMESTAMP ) RETURNS STRUCT DETERMINISTIC LANGUAGE js AS r""" var TextLib = new function () { this.normalize = function(arg) { return arg == null ? '' : arg.replace(/\s+/g, ' ').trim().toLowerCase(); }; this.isEmpty = function(arg) { return this.normalize(arg) == ''; }; this.isNotEmpty = function(arg) { return this.normalize(arg) != ''; }; this.equal = function(left, right) { return this.normalize(left) == this.normalize(right); }; this.notEqual = function(left, right) { return this.normalize(left) != this.normalize(right); }; this.startsWith = function(arg, substring) { return this.normalize(arg).startsWith(this.normalize(substring)); }; this.endsWith = function(arg, substring) { return this.normalize(arg).endsWith(this.normalize(substring)); }; this.contains = function(arg, substring) { return this.normalize(arg).includes(this.normalize(substring)); }; this.containsAll = function(arg, substrings) { if (substrings == null || substrings.length === 0) return false; let normalizedArg = this.normalize(arg); return substrings.every(sub => normalizedArg.includes(this.normalize(sub))); }; this.containsAny = function(arg, substrings) { if (substrings == null || substrings.length === 0) return false; let normalizedArg = this.normalize(arg); return substrings.some(sub => normalizedArg.includes(this.normalize(sub))); }; }(); var references1 = []; // condition[0], conditionIndex:[0..99] references1.push('Deleted From AWS [CA10__disappearanceTime__c]: ' + obj.CA10__disappearanceTime__c); if (obj.CA10__disappearanceTime__c != null) { return {status: 'DISAPPEARED', conditionIndex: 99, conditionText: "isDisappeared(CA10__disappearanceTime__c)", currentStateMessage: "Object is deleted in the source", currentStateReferences: references1.join('\n'), remediation: null, runtimeError: null}; } // condition[1], conditionIndex:[100..199] function fieldChecked4() { if (TextLib.isEmpty(obj.CA10__status__c)) { throw new Error("UNDETERMINED condition:101", {cause: {status: 'UNDETERMINED', conditionIndex: 101, conditionText: "CA10__status__c.delegatedTo(CA10__status__c).isEmpty()", currentStateMessage: "Service status cannot be empty. Possible permission issue with ecs:DescribeServices", currentStateReferences: references1.join('\n'), remediation: null, runtimeError: null}}); } return obj.CA10__status__c; } function extract3() { if (!this.out) { this.out = fieldChecked4(); } return this.out; }; references1.push('Status [obj.CA10__status__c]: ' + obj.CA10__status__c); try { if (TextLib.notEqual(extract3.call(extract3), 'ACTIVE')) { return {status: 'INAPPLICABLE', conditionIndex: 199, conditionText: "extract('CA10__status__c') != 'ACTIVE'", currentStateMessage: "The service is not active.", currentStateReferences: references1.join('\n'), remediation: null, runtimeError: null}; } } catch (err) { if (err.cause && err.cause.status) { return err.cause; } else { throw err; } } // condition[2], conditionIndex:[200..299] function fieldChecked7() { if (TextLib.isEmpty(obj.CA10__assignPublicIp__c)) { throw new Error("UNDETERMINED condition:201", {cause: {status: 'UNDETERMINED', conditionIndex: 201, conditionText: "CA10__assignPublicIp__c.delegatedTo(CA10__assignPublicIp__c).isEmpty()", currentStateMessage: "Service Assign Public IP config cannot be empty. Possible permission issue with ecs:DescribeServices", currentStateReferences: references1.join('\n'), remediation: null, runtimeError: null}}); } return obj.CA10__assignPublicIp__c; } function extract6() { if (!this.out) { this.out = fieldChecked7(); } return this.out; }; references1.push('Assign Public IP [obj.CA10__assignPublicIp__c]: ' + obj.CA10__assignPublicIp__c); try { if (TextLib.equal(extract6.call(extract6), 'Enabled')) { return {status: 'INCOMPLIANT', conditionIndex: 299, conditionText: "extract('CA10__assignPublicIp__c') == 'Enabled'", currentStateMessage: "The ECS service is configured to automatically assign public IP addresses.", currentStateReferences: references1.join('\n'), remediation: "Update the service network configuration to disable auto-assign public IP.", runtimeError: null}; } } catch (err) { if (err.cause && err.cause.status) { return err.cause; } else { throw err; } } // condition[3], conditionIndex:[300..399] function fieldChecked10() { if (TextLib.isEmpty(obj.CA10__assignPublicIp__c)) { throw new Error("UNDETERMINED condition:301", {cause: {status: 'UNDETERMINED', conditionIndex: 301, conditionText: "CA10__assignPublicIp__c.delegatedTo(CA10__assignPublicIp__c).isEmpty()", currentStateMessage: "Service Assign Public IP config cannot be empty. Possible permission issue with ecs:DescribeServices", currentStateReferences: references1.join('\n'), remediation: null, runtimeError: null}}); } return obj.CA10__assignPublicIp__c; } function extract9() { if (!this.out) { this.out = fieldChecked10(); } return this.out; }; try { if (TextLib.equal(extract9.call(extract9), 'Disabled')) { return {status: 'COMPLIANT', conditionIndex: 399, conditionText: "extract('CA10__assignPublicIp__c') == 'Disabled'", currentStateMessage: "The ECS service is configured not to assign public IP addresses.", currentStateReferences: references1.join('\n'), remediation: null, runtimeError: null}; } } catch (err) { if (err.cause && err.cause.status) { return err.cause; } else { throw err; } } return {status: 'UNDETERMINED', conditionIndex: 400, conditionText: "otherwise", currentStateMessage: "Unexpected values in the field.", currentStateReferences: references1.join('\n'), remediation: null, runtimeError: null}; """; SELECT expectedResult.Id as Id, IF ( IFNULL(expectedResult.expectedResult.status, '') = IFNULL(sObject.result.status, '') AND IFNULL(expectedResult.expectedResult.conditionIndex, -1) = IFNULL(sObject.result.conditionIndex, -1) AND IFNULL(expectedResult.expectedResult.conditionText, '') = IFNULL(sObject.result.conditionText, '') AND IFNULL(expectedResult.expectedResult.runtimeError, '') = IFNULL(sObject.result.runtimeError, ''), "MATCH", "FAIL" ) as match, expectedResult.expectedResult.status as expectedStatus, sObject.result.status as actualStatus, expectedResult.expectedResult.conditionIndex as expectedConditionIndex, sObject.result.conditionIndex as actualConditionIndex, expectedResult.expectedResult.conditionText as expectedConditionText, sObject.result.conditionText as actualConditionText, expectedResult.expectedResult.runtimeError as expectedRuntimeError, sObject.result.runtimeError as actualRuntimeError FROM UNNEST(mock_ExpectedResult()) expectedResult LEFT JOIN ( SELECT sObject.CA10__disappearanceTime__c AS CA10__disappearanceTime__c, sObject.CA10__status__c AS CA10__status__c, sObject.CA10__assignPublicIp__c AS CA10__assignPublicIp__c, sObject.Id AS Id, process_CA10__CaAwsEcsService__c( STRUCT( sObject.CA10__disappearanceTime__c AS CA10__disappearanceTime__c, sObject.CA10__status__c AS CA10__status__c, sObject.CA10__assignPublicIp__c AS CA10__assignPublicIp__c, sObject.Id AS Id ), sObject.context.snapshotTime ) as result FROM UNNEST(mock_CA10__CaAwsEcsService__c()) AS sObject ) sObject ON sObject.Id = expectedResult.Id;