responsibility-model
) with matching inventory.In general, the following information is needed to add a new assessment:
SNS-ENCRYPTION-FR
)
-FR
suffix indicates that this is a FedRAMP assessment.Example:
In general, the evaluations for assessments were defined in this spreadsheet.
For more complex assessments, it may be valuable to write an assessment definition following this template.
Example assessment definition.
Example directory structure for a new assessment:
1 2src/controls/epm/rdsEncryption/ ├── __tests__ │ └── rdsEncryptedRule.test.ts ├── actions │ └── rdsEncryptedAction.ts ├── control.ts ├── index.ts ├── queries │ └── batch.sql └── rules └── rdsEncryptedRule.ts
Notes:
actions
- Intervention actions resulting from failed assessment (i.e. Slack message, Jira ticket)queries
- SQL queries to run for the assessmentrules
- Rules that define the logic for the assessment, including the query to run and the expected resultscontrol.ts
- Control metadata, including the control key, description, and asset class. Triggers are often defined here as wellAn example PR for a new assessment can be found here.
Create a SQL query for Socrates vNext that will be used to assess the asset class. The query should return the necessary fields to determine compliance with the control.
Example query:
1 2WITH rds_dbs AS ( SELECT case_data.arn, MAX(case_data.hour) AS max_hour FROM {{ caseTableName }} AS case_data WHERE case_data.service = "RDS" AND case_data.resource = "DBInstance" GROUP BY case_data.arn ) SELECT DISTINCT case_data.arn AS asset_id, "AWS-RDS" AS asset_class, GET_JSON_OBJECT(case_data.tags, "$.micros_service_id") AS service_id, CAST(COALESCE( GET_JSON_OBJECT(case_data.configuration, "$.storageEncrypted"), GET_JSON_OBJECT(case_data.configuration, "$.StorageEncrypted"), GET_JSON_OBJECT(case_data.configuration, "$.encrypted"), GET_JSON_OBJECT(case_data.configuration, "$.IsEncrypted"), FALSE ) AS BOOLEAN) AS is_encrypted FROM {{ caseTableName }} AS case_data INNER JOIN rds_dbs ON case_data.arn = rds_dbs.arn AND case_data.hour = rds_dbs.max_hour INNER JOIN {{ awsAccountsTableName }} AS aa ON case_data.awsaccountid = aa.id;
Note: Field names from this query are asset_id
, asset_class
, service_id
, and is_encrypted
. The {{ caseTableName }}
and {{ awsAccountsTableName }}
are placeholders that will be replaced by the actual table names when the query is executed.
Create a trigger that runs the SQL query on a schedule. The trigger can be defined in a class that extends TemplatedBatchTrigger
to take advantage of a templated query. A templated query is particularly useful when running the same query against different table names such as those found in-boundary. The trigger will use the SQL query defined at the given path and substitute the supplied variables.
Example trigger for daily RDS encryption assessment:
1 2class RdsEncryptedTrigger extends TemplatedBatchTrigger { constructor(tableName: string, awsAccountTableName: string) { super({ sqlPath: 'controls/epm/rdsEncryption/queries/batch.sql', replacements: { caseTableName: tableName, awsAccountsTableName: awsAccountTableName, }, }); } metadata(): BatchMetadata { return new BatchMetadata('rds_encrypted_batch_trigger', TriggerFrequency.DAILY); } queryEvidenceMapping(): Record<string, EvidenceFieldDef> { return { asset_id: new EvidenceFieldDef('asset_id', String, false), asset_class: new EvidenceFieldDef('asset_class', String, false), service_id: new EvidenceFieldDef('service_id', String, true), is_encrypted: new EvidenceFieldDef('is_encrypted', Boolean, false), }; } }
Note: The queryEvidenceMapping
defines the fields from the query to use as evidence.
Create an action that will be triggered when the assessment fails. This action can send a Slack message or create a Jira ticket, depending on your requirements.
Example action for sending a Slack notification:
1 2export class RdsEncryptedAction implements ActionRequest { get metadata(): ActionRequestMetadata { return new ActionRequestMetadata( 'rds_encrypted_recommendation', 'Slack notification which alerts service owners to ensure their AWS RDS encryption at rest is enabled', ); } shouldRaise(outcomes: RuleOutcomes) { return new EQ(outcomes.of('rds_encrypted'), false); } action(evidence: Record<string, unknown>): SlackAction { const assetId = evidence.asset_id as string; const serviceId = evidence.service_id as string; const message = `Enterprise Posture Management has detected a RDS asset ${assetId} is not encrypted at rest. Please review the actionable items under the "Protect confidentiality and integrity of data at rest" Criteria in the Enterprise Posture Management Dashboard.`; let url = 'https://resp-model-ui-public.us-east-1.prod.public.atl-paas.net/components/'; if ((serviceId || '').trim()) { url = `https://resp-model-ui-public.us-east-1.prod.public.atl-paas.net/components/${serviceId}/d21a4e50-26fc-4521-925b-875cbe78fa4e`; } return new SlackAction(message, url, null); } }
Create a rule that defines the logic for the assessment. Rules use evidence fields to determine an outcome for an assessment.
Example rule to check if RDS encryption is enabled:
1 2export class RdsEncryptedRule extends Rule { evaluate(evidence: Evidence): RuleOutcome { const encrypted = evidence.getField('is_encrypted'); const expression = new EQ(encrypted, true); return new RuleOutcome('rds_encrypted', 'Checks whether the AWS RDS resource has encryption enabled', expression); } }
Create a control that ties everything together. This control will define the control key, description, and the action to take when the assessment fails.
1 2export const RdsEncryption = buildEpmControl({ active: true, owner: 'jdoe', key: 'RDS-DB-ENCRYPTION', tags: ['rds', 'standards', 'encryption'], supportChannel: new SupportChannel( '#help-enterprise-posture-management', 'https://atlassian.enterprise.slack.com/archives/C02H23XU943', ), rules: [new RdsEncryptedRule()], trigger: new RdsEncryptedTrigger(COMMERCIAL_CASE_TABLE_NAME, COMMERCIAL_AWS_ACCOUNTS_TABLE_NAME), actions: [new RdsEncryptedAction()], perimeters: [MicrosPerimeter.COMMERCIAL], name: null, enrichments: [], applicabilityRule: null, businessUnit: null, opsgenieNotifications: null, });
Since assessments are only run once daily, it may be valuable to manually test an assessment via the REST API. Call /api/v1/evidence/collect/<CONTROL_KEY>?limit=-1
with the control key to trigger assessments for a specific control.
All in-boundary assessment results are subject to the transit policy. The change in this PR will obfuscate ARNs for all asset classes starting with AWS
, Aws
, or aws
. This means any other asset classes will be dropped from transit out of boundary.
Rate this page: