
Ferramenta de linting para templates CloudFormation
A ferramenta cfn-nag procura padrões em modelos do CloudFormation que possam indicar infraestrutura insegura. De modo geral, ela procurará por:
Para mais informações sobre a ferramenta, consulte esta publicação no blog da Stelligent:
Supondo que Ruby >= 2.5.x esteja instalado, a instalação é apenas uma questão de:
gem install cfn-nag
No MacOS ou Linux, você pode instalar alternativamente com brew:
brew install ruby brew-gem
brew gem install cfn-nag
Para executar cfn_nag como uma ação no CodePipeline, você pode implantar via AWS Serverless Application Repository.
Para executar:
cfn_nag_scan --input-path <path to cloudformation json>
O caminho pode ser um diretório ou um modelo específico. Se for um diretório, todos os arquivos .json, .template, .yml e .yaml serão processados, incluindo recursão em subdiretórios.
O formato de saída padrão é texto livre, mas a saída em json pode ser selecionada com a flag --output-format json.
Opcionalmente, uma flag --debug despeja informações sobre os detalhes internos do carregamento de regras.
Execute com --help para uma lista completa das opções suportadas.
Para ver uma lista de todas as regras que o cfn-nag suporta atualmente, há um utilitário de linha de comando que as envia para stdout:
cfn_nag_rules
Um Dockerfile é fornecido para conveniência. Ele é publicado no DockerHub como stelligent/cfn_nag.
https://hub.docker.com/r/stelligent/cfn_nag
Você também pode compilá-lo localmente.
docker build -t stelligent/cfn_nag .
Você pode montar um diretório local contendo modelos no contêiner Docker e então chamar o cfn_nag no contêiner. Este exemplo usa os modelos de teste usados nos testes unitários do cfn_nag:
$ docker run -v `pwd`/spec/test_templates:/templates -t stelligent/cfn_nag /templates/json/efs/filesystem_with_encryption.json
{
"failure_count": 0,
"violations": [
]
}
$ docker run -v `pwd`/spec/test_templates:/templates -t stelligent/cfn_nag /templates/json/efs/filesystem_with_no_encryption.json
{
"failure_count": 1,
"violations": [
{
"id": "F27",
"type": "FAIL",
"message": "EFS FileSystem should have encryption enabled",
"logical_resource_ids": [
"filesystem"
]
}
]
}
cfn_nag_scan pode ser executado como parte de um GitHub Workflow para avaliar o código durante pipelines de integração contínua.
No seu arquivo de GitHub Workflow, crie uma etapa que use a cfn_nag Action:
- name: Simple test
uses: stelligent/cfn_nag@master
with:
input_path: tests
Mais informações sobre a GitHub Action podem ser encontradas aqui.
O cfn-nag suporta a noção de um "perfil", que é efetivamente uma lista de permissões de regras a aplicar. O perfil é um arquivo de texto que deve conter um identificador de regra por linha. Quando especificado via argumento de linha de comando --profile-path, o cfn-nag retornará SOMENTE violações dessas regras específicas.
A motivação por trás da criação de um "perfil" é que diferentes desenvolvedores podem se importar com regras diferentes. Por exemplo, um "infrastructure_developer" pode se importar com regras de IAM, enquanto um "app_developer" pode nem conseguir criar recursos IAM e, portanto, não se importar com essas regras.
Aqui está um exemplo de perfil:
F1
F2
F27
W3
W5
A lista de negação é basicamente o oposto do perfil: é uma lista de regras que NUNCA devem ser aplicadas. Quando especificada via argumento de linha de comando --deny-list-path, o cfn-nag NUNCA retornará violações dessas regras específicas especificadas no arquivo.
Caso uma regra seja especificada em ambos, a lista de negação terá prioridade sobre o perfil, e a regra não será aplicada.
O formato é o seguinte. Os únicos dois campos relevantes são RulesToSuppress e o id de cada item. O reason não será interpretado pelo cfn-nag, mas é recomendado para justificar e documentar por que a regra nunca deve ser aplicada.
RulesToSuppress:
- id: W3
reason: W3 is something we never care about at enterprise X
Caso exista uma regra que você queira suprimir, uma chave Metadata do cfn_nag pode ser adicionada ao recurso afetado para dizer ao cfn_nag para não gerar uma falha ou aviso para essa regra.
Por exemplo, se você estiver configurando um ELB público aberto a conexões de entrada da internet com recursos como os seguintes:
public_alb.yaml
# Partial template
PublicAlbSecurityGroup:
Properties:
GroupDescription: 'Security group for a public Application Load Balancer'
VpcId:
Ref: vpc
Type: AWS::EC2::SecurityGroup
PublicAlbSecurityGroupHttpIngress:
Properties:
CidrIp: 0.0.0.0/0
FromPort: 80
GroupId:
Ref: PublicAlbSecurityGroup
IpProtocol: tcp
ToPort: 80
Type: AWS::EC2::SecurityGroupIngress
O cfn_nag emitirá avisos como os seguintes:
$ cfn_nag_scan -i public_alb.yaml
------------------------------------------------------------
public_alb.yaml
------------------------------------------------------------------------------------------------------------------------
| WARN W9
|
| Resources: ["PublicAlbSecurityGroup"]
|
| Security Groups found with ingress cidr that is not /32
------------------------------------------------------------
| WARN W2
|
| Resources: ["PublicAlbSecurityGroup"]
|
| Security Groups found with cidr open to world on ingress. This should never be true on instance. Permissible on ELB
Failures count: 0
Warnings count: 2
Ao adicionar os metadados, esses avisos podem ser suprimidos:
public_alb_with_suppression.yaml
# Partial template
PublicAlbSecurityGroup:
Properties:
GroupDescription: 'Security group for a public Application Load Balancer'
VpcId:
Ref: vpc
Type: AWS::EC2::SecurityGroup
Metadata:
cfn_nag:
rules_to_suppress:
- id: W9
reason: "This is a public facing ELB and ingress from the internet should be permitted."
- id: W2
reason: "This is a public facing ELB and ingress from the internet should be permitted."
PublicAlbSecurityGroupHttpIngress:
Properties:
CidrIp: 0.0.0.0/0
FromPort: 80
GroupId:
Ref: PublicAlbSecurityGroup
IpProtocol: tcp
ToPort: 80
Type: AWS::EC2::SecurityGroupIngress