-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(aws-foundational): Initial commit
- Loading branch information
1 parent
f8d426a
commit 980a85e
Showing
18 changed files
with
593 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,5 @@ | ||
# policies-premium | ||
# Premium Policies | ||
|
||
Premium policies for CloudQuery plugins. | ||
|
||
Policies are split by plugin and then by policy type. Each policy can have multiple ports for different databases (for example Snowflake and BigQuery). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
.env | ||
__pycache__ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
# AWS Foundational Security Best Practices pack with Snowflake SQL | ||
|
||
## Requirements | ||
|
||
### CloudQuery Sync | ||
|
||
Make sure you synced your AWS metadata with CloudQuery [AWS source plugin](https://www.cloudquery.io/docs/plugins/sources/overview) and [Snowflake destinatio](https://www.cloudquery.io/docs/plugins/destinations/snowflake/overview). | ||
|
||
### Run the policy | ||
|
||
- Install Python > 3.8 | ||
- Run `pip install -r requirements.txt` | ||
- Run `cp env.example` to `.env` and fill the snowflake environment credentials | ||
- Run `python main.py` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
SNOW_USER= | ||
SNOW_PASS= | ||
SNOW_ACCOUNT= | ||
SNOW_WAREHOUSE= | ||
SNOW_DATABASE= | ||
SNOW_SCHEMA= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
|
||
import os | ||
import sys | ||
import datetime | ||
import argparse | ||
import sections | ||
import snowflake.connector | ||
|
||
from dotenv import load_dotenv | ||
|
||
load_dotenv() # take environment variables from .env. | ||
|
||
def run_policy(args): | ||
print("Running doundational Security Policy") | ||
conn = snowflake.connector.connect( | ||
user=os.environ.get("SNOW_USER"), | ||
password=os.environ.get("SNOW_PASSWORD"), | ||
account=os.environ.get("SNOW_ACCOUNT"), | ||
warehouse=os.environ.get("SNOW_WAREHOUSE"), | ||
database=os.environ.get("SNOW_DATABASE"), | ||
schema=os.environ.get("SNOW_SCHEMA"), | ||
) | ||
execution_time = datetime.datetime.now() | ||
# sections.execute_account(conn, execution_time) | ||
# sections.execute_acm(conn, execution_time) | ||
# sections.execute_apigateway(conn, execution_time) | ||
# sections.execute_awsconfig(conn, execution_time) | ||
# sections.execute_cloudfront(conn, execution_time) | ||
# sections.execute_cloudtrail(conn, execution_time) | ||
# sections.execute_codebuild(conn, execution_time) | ||
sections.execute_dynamodb(conn, execution_time) | ||
print("Finished running doundational security policy") | ||
|
||
def create_views(args): | ||
pass | ||
|
||
def main(): | ||
parser = argparse.ArgumentParser( | ||
prog='aws-foundational-snowflake', | ||
description='Foundational security policy with Snowflake SQL') | ||
subparsers = parser.add_subparsers(help='sub-command help', required=True) | ||
parser_run_policy = subparsers.add_parser('run-policy', help='run policy') | ||
parser_run_policy.set_defaults(func=run_policy) | ||
parser_create_views = subparsers.add_parser('create-view', help='create all required views') | ||
parser_create_views.set_defaults(func=run_policy) | ||
args = parser.parse_args(sys.argv[1:]) | ||
args.func(args) | ||
|
||
|
||
if __name__ == '__main__': | ||
main() |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
|
||
|
||
|
||
SECURITY_ACCOUNT_INFORMATION_PROVIDED = """ | ||
INSERT INTO aws_policy_results | ||
SELECT | ||
%s as execution_time, | ||
%s as framework, | ||
%s as check_id, | ||
'Security contact information should be provided for an AWS account' AS "title", | ||
'aws_iam_accounts.account_id' as "account_id", | ||
'aws_iam_accounts.account_id' as "resource_id", | ||
CASE WHEN | ||
'alternate_contact_type' IS NULL | ||
THEN 'fail' | ||
ELSE 'pass' | ||
END AS "status" | ||
FROM aws_iam_accounts | ||
LEFT JOIN ( | ||
SELECT * FROM aws_account_alternate_contacts | ||
WHERE 'alternate_contact_type' = 'SECURITY' | ||
) AS account_security_contacts | ||
ON 'aws_iam_accounts.account_id' = 'account_security_contacts.account_id' | ||
""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import datetime | ||
from snowflake.connector import SnowflakeConnection | ||
|
||
CERTIFICATES_SHOULD_BE_RENEWED = """ | ||
insert into aws_policy_results | ||
select | ||
%s as execution_time, | ||
%s as framework, | ||
%s as check_id, | ||
'certificate has less than 30 days to be renewed' as title, | ||
account_id, | ||
arn AS resource_id, | ||
case when | ||
not_after < DATEADD('day', 30, CURRENT_TIMESTAMP()::timestamp_ntz) | ||
then 'fail' | ||
else 'pass' | ||
end as status | ||
FROM aws_acm_certificates | ||
""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
|
||
API_GW_EXECUTION_LOGGING_ENABLED = """ | ||
insert into aws_policy_results | ||
(select distinct | ||
%s as execution_time, | ||
%s as framework, | ||
%s as check_id, | ||
'API Gateway REST and WebSocket API logging should be enabled' as title, | ||
r.account_id, | ||
'arn:' || 'aws' || ':apigateway:' || r.region || ':/restapis/' || r.id as resource_id, | ||
case | ||
when s.logging_level not in ('"ERROR"', '"INFO"') then 'fail' | ||
else 'pass' | ||
end as status | ||
from | ||
view_aws_apigateway_method_settings s | ||
left join | ||
aws_apigateway_rest_apis r on s.rest_api_arn = r.arn | ||
) | ||
union | ||
(select distinct | ||
%s as execution_time, | ||
%s as framework, | ||
%s as check_id, | ||
'API Gateway REST and WebSocket API logging should be enabled' as title, | ||
a.account_id, | ||
'arn:' || 'aws' || ':apigateway:' || a.region || ':/apis/' || a.id as resource_id, | ||
case | ||
WHEN s.default_route_settings:LoggingLevel IN (NULL, 'OFF') THEN 'fail' | ||
else 'pass' | ||
end as status | ||
from | ||
aws_apigatewayv2_api_stages s | ||
left join | ||
aws_apigatewayv2_apis a on s.api_arn = a.arn | ||
) | ||
""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
|
||
ENABLED_ALL_REGIONS = """ | ||
insert into aws_policy_results | ||
select | ||
%s as execution_time, | ||
%s as framework, | ||
%s as check_id, | ||
'AWS Config should be enabled' as title, | ||
account_id, | ||
arn as resource_id, | ||
CASE | ||
WHEN ((recording_group:IncludeGlobalResourceTypes::BOOLEAN != TRUE) OR (recording_group:AllSupported::BOOLEAN != TRUE) OR (status_recording != TRUE OR status_last_status != 'SUCCESS')) | ||
THEN 'fail' | ||
ELSE 'pass' | ||
END AS status | ||
FROM | ||
aws_config_configuration_recorders | ||
""" |
119 changes: 119 additions & 0 deletions
119
aws/foundational_security/snowflake/queries/cloudfront.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
|
||
DEFAULT_ROOT_OBJECT_CONFIGURED = """ | ||
insert into aws_policy_results | ||
select | ||
%s as execution_time, | ||
%s as framework, | ||
%s as check_id, | ||
'CloudFront distributions should have a default root object configured' as title, | ||
account_id, | ||
arn as resource_id, | ||
CASE | ||
WHEN distribution_config:DefaultRootObject::STRING = '' THEN 'fail' | ||
ELSE 'pass' | ||
END AS status | ||
from aws_cloudfront_distributions | ||
""" | ||
|
||
ORIGIN_ACCESS_IDENTITY_ENABLED = """ | ||
insert into aws_policy_results | ||
select | ||
%s as execution_time, | ||
%s as framework, | ||
%s as check_id, | ||
'CloudFront distributions should have origin access identity enabled' as title, | ||
account_id, | ||
arn as resource_id, | ||
CASE | ||
WHEN o.value:DomainName::STRING LIKE '%%s3.amazonaws.com' AND o.value:S3OriginConfig:OriginAccessIdentity::STRING = '' THEN 'fail' | ||
ELSE 'pass' | ||
END AS status | ||
from aws_cloudfront_distributions, LATERAL FLATTEN(input => distribution_config:Origins:Items) o | ||
""" | ||
|
||
VIEWER_POLICY_HTTPS = """ | ||
insert into aws_policy_results | ||
WITH cachebeviors AS ( | ||
-- Handle all non-defaults as well as when there is only a default route | ||
SELECT DISTINCT arn, account_id | ||
FROM ( | ||
SELECT arn, account_id, d.value AS CacheBehavior | ||
FROM aws_cloudfront_distributions, | ||
LATERAL FLATTEN(input => distribution_config:CacheBehaviors:Items) AS d | ||
WHERE distribution_config:CacheBehaviors:Items IS NOT NULL | ||
UNION | ||
-- Handle default Cachebehaviors | ||
SELECT arn, account_id, distribution_config:DefaultCacheBehavior AS CacheBehavior | ||
FROM aws_cloudfront_distributions | ||
) AS cachebeviors | ||
WHERE CacheBehavior:ViewerProtocolPolicy::STRING = 'allow-all' | ||
) | ||
select | ||
%s as execution_time, | ||
%s as framework, | ||
%s as check_id, | ||
'CloudFront distributions should require encryption in transit' as title, | ||
account_id, | ||
arn as resource_id, | ||
'fail' as status | ||
from cachebeviors | ||
""" | ||
|
||
ORIGIN_FAILOVER_ENABLED = """ | ||
insert into aws_policy_results | ||
with origin_groups as ( select acd.arn, distribution_config:OriginGroups:Items as ogs from aws_cloudfront_distributions acd), | ||
oids as ( | ||
select distinct | ||
account_id, | ||
acd.arn as resource_id, | ||
case | ||
when o.ogs = 'null' or | ||
o.ogs:Members:Items = 'null' or | ||
ARRAY_SIZE(o.ogs:Members:Items) = 0 then 'fail' | ||
else 'pass' | ||
end as status | ||
from aws_cloudfront_distributions acd | ||
left join origin_groups o on o.arn = acd.arn | ||
) | ||
select | ||
%s as execution_time, | ||
%s as framework, | ||
%s as check_id, | ||
'CloudFront distributions should have origin failover configured' as title, | ||
account_id, | ||
resource_id, | ||
status | ||
from oids | ||
""" | ||
|
||
ACCESS_LOGS_ENABLED = """ | ||
insert into aws_policy_results | ||
select | ||
%s as execution_time, | ||
%s as framework, | ||
%s as check_id, | ||
'CloudFront distributions should have logging enabled' as title, | ||
account_id, | ||
arn as resource_id, | ||
case | ||
when (distribution_config:Logging:Enabled)::boolean is distinct from true then 'fail' | ||
else 'pass' | ||
end as status | ||
from aws_cloudfront_distributions | ||
""" | ||
|
||
ASSOCIATED_WITH_WAF = """ | ||
insert into aws_policy_results | ||
select | ||
%s as execution_time, | ||
%s as framework, | ||
%s as check_id, | ||
'API Gateway should be associated with an AWS WAF web ACL' as title, | ||
account_id, | ||
arn as resource_id, | ||
case | ||
when distribution_config:WebACLId = '' then 'fail' | ||
else 'pass' | ||
end as status | ||
from aws_cloudfront_distributions | ||
""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
|
||
ENABLED_ALL_REGIONS = """ | ||
insert into aws_policy_results | ||
select | ||
%s as execution_time, | ||
%s as framework, | ||
%s as check_id, | ||
'Ensure CloudTrail is enabled in all regions' as title, | ||
aws_cloudtrail_trails.account_id, | ||
arn as resource_id, | ||
case | ||
when is_multi_region_trail = FALSE or ( | ||
is_multi_region_trail = TRUE and ( | ||
read_write_type != 'All' or include_management_events = FALSE | ||
)) then 'fail' | ||
else 'pass' | ||
end as status | ||
from aws_cloudtrail_trails | ||
inner join | ||
aws_cloudtrail_trail_event_selectors on | ||
aws_cloudtrail_trails.arn = aws_cloudtrail_trail_event_selectors.trail_arn | ||
and aws_cloudtrail_trails.region = aws_cloudtrail_trail_event_selectors.region | ||
and aws_cloudtrail_trails.account_id = aws_cloudtrail_trail_event_selectors.account_id | ||
""" | ||
|
||
LOGS_ENCRYPTED = """ | ||
insert into aws_policy_results | ||
select | ||
%s as execution_time, | ||
%s as framework, | ||
%s as check_id, | ||
'CloudTrail should have encryption at rest enabled' as title, | ||
account_id, | ||
arn as resource_id, | ||
case | ||
when kms_key_id is NULL then 'fail' | ||
else 'pass' | ||
end as status | ||
FROM aws_cloudtrail_trails | ||
""" | ||
|
||
LOGS_FILE_VALIDATION_ENABLED = """ | ||
insert into aws_policy_results | ||
select | ||
%s as execution_time, | ||
%s as framework, | ||
%s as check_id, | ||
'Ensure CloudTrail log file validation is enabled' as title, | ||
account_id, | ||
arn as resource_id, | ||
case | ||
when log_file_validation_enabled = false then 'fail' | ||
else 'pass' | ||
end as status | ||
from aws_cloudtrail_trails | ||
""" | ||
|
||
INTEGRATED_WITH_CLOUDWATCH_LOGS = """ | ||
INSERT INTO aws_policy_results | ||
SELECT | ||
%s as execution_time, | ||
%s as framework, | ||
%s as check_id, | ||
'CloudTrail trails should be integrated with CloudWatch Logs' as title, | ||
account_id, | ||
arn as resource_id, | ||
CASE | ||
WHEN cloud_watch_logs_log_group_arn IS NULL | ||
OR TO_TIMESTAMP(status:LatestCloudWatchLogsDeliveryTime) < DATEADD('day', -1, CURRENT_TIMESTAMP()) | ||
THEN 'fail' | ||
ELSE 'pass' | ||
END as status | ||
FROM aws_cloudtrail_trails | ||
""" |
Oops, something went wrong.