Skip to content

Commit

Permalink
feat(aws-foundational): Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
yevgenypats committed Jul 20, 2023
1 parent f8d426a commit 980a85e
Show file tree
Hide file tree
Showing 18 changed files with 593 additions and 1 deletion.
5 changes: 4 additions & 1 deletion README.md
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).
2 changes: 2 additions & 0 deletions aws/foundational_security/snowflake/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.env
__pycache__
14 changes: 14 additions & 0 deletions aws/foundational_security/snowflake/README.md
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`
6 changes: 6 additions & 0 deletions aws/foundational_security/snowflake/env.example
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=
51 changes: 51 additions & 0 deletions aws/foundational_security/snowflake/main.py
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.
24 changes: 24 additions & 0 deletions aws/foundational_security/snowflake/queries/account.py
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'
"""
19 changes: 19 additions & 0 deletions aws/foundational_security/snowflake/queries/acm.py
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
"""
39 changes: 39 additions & 0 deletions aws/foundational_security/snowflake/queries/apigateway.py
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
)
"""
18 changes: 18 additions & 0 deletions aws/foundational_security/snowflake/queries/awsconfig.py
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 aws/foundational_security/snowflake/queries/cloudfront.py
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
"""
74 changes: 74 additions & 0 deletions aws/foundational_security/snowflake/queries/cloudtrail.py
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
"""
Loading

0 comments on commit 980a85e

Please sign in to comment.