La herramienta CFN-NAG busca patrones en plantillas de formación de nubes que puedan indicar infraestructura insegura. En términos generales, buscará:
Para obtener más información sobre la herramienta, consulte esta publicación en el blog de Stelligent:
Encontrar problemas de seguridad temprano en el proceso de desarrollo de una plantilla de CloudFormation con "CFN-NAG"
Suponiendo que Ruby> = 2.5.x está instalada, la instalación es solo una cuestión de:
gem install cfn-nagEn MacOS o Linux, puede instalar alternativamente con Brew:
brew install ruby brew-gem
brew gem install cfn-nag Para ejecutar cfn_nag como una acción en CodePipeline, puede implementar a través del repositorio de aplicaciones sin servidor AWS.
Para ejecutar:
cfn_nag_scan --input-path < path to cloudformation json > La ruta puede ser un directorio o una plantilla particular. Si se trata de un directorio, todos los archivos .json, .template , .yml y .yaml se procesarán, incluidos los recursos en subdirectorios.
El formato de salida predeterminado es el texto de forma libre, pero la salida de JSON se puede seleccionar con el indicador --output-format json .
Opcionalmente, una bandera --debug arrojará información sobre las partes internas de la carga de reglas.
Ejecute con --help para una lista completa de interruptores compatibles.
Para ver una lista de todas las reglas que CFN-NAG actualmente admite, hay una utilidad de línea de comandos que las arrojará a Stdout:
cfn_nag_rules Se proporciona un Dockerfile por conveniencia. Se publica en Dockerhub como stelligent/cfn_nag .
https://hub.docker.com/r/stelligent/cfn_nag
También puedes construirlo localmente.
docker build -t stelligent/cfn_nag .Puede montar un directorio local que contiene plantillas en el contenedor Docker y luego llamar a CFN_NAG en el contenedor. Este ejemplo usa las plantillas de prueba utilizadas en la unidad de prueba 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 se puede ejecutar como parte de un flujo de trabajo GitHub para evaluar el código durante las tuberías de integración continua.
En su archivo de flujo de trabajo GitHub, cree un paso que use la acción CFN_NAG:
- name : Simple test
uses : stelligent/cfn_nag@master
with :
input_path : testsPuede encontrar más información sobre la acción de GitHub aquí.
CFN-NAG admite la noción de un "perfil" que es efectivamente una lista permitida de reglas. El perfil es un archivo de texto que debe contener un identificador de regla por línea. Cuando se especifica a través del argumento de línea de comandos --profile-path , CFN-NAG solo devolverá las violaciones de esas reglas particulares.
La motivación detrás de crear un "perfil" es que a los diferentes desarrolladores les importan diferentes reglas. Por ejemplo, un "infraestructura_developer" podría preocuparse por las reglas de IAM, mientras que un "App_developer" podría no poder crear recursos de IAM y, por lo tanto, no preocuparse por esas reglas.
Aquí hay un perfil de ejemplo:
F1
F2
F27
W3
W5
La lista de Deny es básicamente lo opuesto al perfil: es una lista de reglas para nunca aplicar. Cuando se especifica a través del argumento --deny-list-path Line Line, CFN-NAG nunca devolverá las violaciones de esas reglas particulares especificadas en el archivo.
En caso de que se especifique una regla en ambas, la lista Deny tendrá prioridad sobre el perfil y la regla no se aplicará.
El formato es el siguiente. Los únicos dos campos sobresalientes son RulesToSuppress y la id por artículo. La reason no será interpretada por CFN-NAG, pero se recomienda justificar y documentar por qué la regla nunca debe aplicarse.
RulesToSuppress :
- id : W3
reason : W3 is something we never care about at enterprise X En el caso de que haya una regla que desee suprimir, se puede agregar una clave Metadata cfn_nag al recurso afectado para decirle a CFN_NAG que no plantee una falla o advertencia para esa regla.
Por ejemplo, si está configurando un ELB con orientación pública que está abierta a conexiones entrantes desde Internet con recursos como los siguientes:
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::SecurityGroupIngressCFN_NAG planteará advertencias como las siguientes:
$ 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: 2Al agregar los metadatos, estas advertencias se pueden suprimir:
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 $ cfn_nag_scan -i public_alb_with_suppression.yaml
------------------------------------------------------------
public_alb_with_supression.yaml
------------------------------------------------------------
Failures count: 0
Warnings count: 0Los parámetros de la plantilla de CloudFormation pueden presentar un problema para el análisis estático, ya que los valores se especifican en el punto de implementación. En otras palabras, los valores no están disponibles cuando se realiza el análisis estático: el análisis estático solo puede observar el "código" que está frente a él. Por lo tanto, una regla de entrada del grupo de seguridad de 0.0.0.0/0 no se marcará si el CIDR se parametriza y el 0.0.0.0/0 se pasa en el tiempo de implementación.
Para permitir la comprobación de los valores de los parámetros, un usuario puede especificar los valores de parámetros en un archivo JSON que se pasa en la línea de comando en cfn_nag y cfn_nag_scan con la bandera --parameter-values-path=<filename/uri> .
El formato del JSON es una clave única, "Parámetros", cuyo valor es un diccionario con cada mapeo de pares de clave/valor a los parámetros:
{
"Parameters" : {
"Cidr" : " 0.0.0.0/0 "
}
}Esto proporcionará "0.0.0.0/0" al siguiente parámetro:
Parameters :
Cidr :
Type : String Tenga en cuenta que si hay parámetros adicionales en el JSON, se ignoran silenciosamente (para permitir que cfn_nag_scan aplique el mismo JSON en todas las plantillas).
Si el JSON está malformado o no cumple con la especificación anterior, entonces el análisis fallará con una violación fatal.
Antes de 0.5.55, las llamadas a FN :: FindInmap fueron ignoradas efectivamente. El modelo subyacente los dejaría, por lo que aparecerían como un hash valores para las reglas. Por ejemplo: { "Fn::FindInMap" => [map1, key1, key2]}
A partir de 0.5.55, el modelo intentará calcular el valor para una llamada a FindInmap y presentar ese valor a las reglas. Esta evaluación admite claves que son:
Si la lógica de evaluación no puede encontrar el valor de una clave, el por defecto será el comportamiento anterior de devolver el hash para toda la expresión.
También antes de 0.5.55, las llamadas a las pseudofunciones de AWS se ignoraron efectivamente. El modelo subyacente los dejaría, por lo que aparecerían como un hash valores para las reglas. Por ejemplo: {"Ref"=>"AWS::Region"} . Un caso de uso común es organizar las asignaciones por región, por lo que la evaluación de la pseudofunción es importante para apoyar mejor la evaluación del mapa.
A partir de 0.5.55, el modelo presentará las siguientes pseudofunciones de AWS a las reglas con los valores predeterminados:
'AWS::URLSuffix' => 'amazonaws.com',
'AWS::Partition' => 'aws',
'AWS::NotificationARNs' => '',
'AWS::AccountId' => '111111111111',
'AWS::Region' => 'us-east-1',
'AWS::StackId' => 'arn:aws:cloudformation:us-east-1:111111111111:stack/stackname/51af3dc0-da77-11e4-872e-1234567db123',
'AWS::StackName' => 'stackname'
Además, el usuario final puede anular el valor suministrado a través del mecanismo de sustitución de parámetros tradicional. Por ejemplo:
{
"Parameters" : {
"AWS::Region" : " eu-west-1 "
}
}Hasta la versión 0.4.66 de CFN_NAG, el modelo subyacente no realizó ningún procesamiento de fn :: si está dentro de una plantilla. Esto significaba que si una propiedad tenía un valor condicional, dependía de la regla analizar el fn :: si. Dado que un FN :: si podría aparecer en casi cualquier lugar, creó una situación de Whack-A-Mole para los desarrolladores de reglas. En el mejor de los casos, la lógica de la regla podría ignorar los valores que eran hash suponiendo que el valor no fuera un hash en primer lugar.
Para abordar este problema, el comportamiento predeterminado para CFN_NAG ahora es sustituir FN :: si es con el verdadero resultado. Esto significa que por defecto que las reglas no inspeccionarán los resultados falsos por violaciones de seguridad.
Además de sustituir FN :: si está en el nivel de valor de la propiedad, se aplica el mismo comportamiento a FN :: si está en el nivel superior de propiedades. Por ejemplo:
Resource1 :
Type : Foo
Properties : !If
- IsNone
- Description : Up
- Description : DOwnSe verá igual que:
Resource1 :
Type : Foo
Properties :
Description : Up Para proporcionar cierto control sobre este comportamiento, un usuario puede especificar los valores de condición en un archivo JSON que se pasa en la línea de comandos a cfn_nag y cfn_nag_scan con la bandera --condition-values-path=<filename/uri> .
El formato del JSON es un diccionario AA con cada mapeo de pares de clave/valor a las condiciones:
{
"Condition1" : true ,
"Condition2" : false
}La base para SPCM se describe en el Blog Public Public Tople Experiment Metric de complejidad para los documentos de política IAM.
Comenzando en la versión 0.6.0 de CFN_NAG:
spcm_scan puede escanear un directorio de plantillas de formación de nubes (como CFN_NAG_SCAN) y generar un informe con las métricas SPCM en formato JSON o HTMLcfn_nag_scan --rule-arguments spcm_threshold:100--rule-arguments . El objeto de la regla solo necesita declarar un attr_accessor , por ejemplo, attr_accessor :spcm_threshold y cfn_nag se encargará de los detalles para inyectar valores de los --rule-arguments La liberación de 0.5.x incluye algunos cambios importantes en la forma en que las reglas personalizadas (CAN) se distribuyen y cargan. Antes de esta versión, había dos lugares donde se cargaron las reglas: el directorio lib/cfn-nag/custom_rules dentro del núcleo CFN_NAG GEM, y el directorio de regla personalizada especificado en la línea de comandos.
Hay dos casos de uso que forzaron un rediseño de cómo/dónde se cargan las reglas personalizadas. El mecanismo de carga de reglas se ha generalizado de tal manera que los repositorios de reglas personalizados se pueden usar para descubrir reglas.
Un montón de "archivos de reglas" sentados en un sistema de archivos no es excelente desde una perspectiva de desarrollo de software tradicional. No hay versión o trazabilidad en estos archivos, por lo que 0.5.x introduce la noción de una "gema de reglas CFN_NAG". Un desarrollador puede desarrollar reglas personalizadas como parte de una gema separada, la versión e instalarla ... y esas reglas se hacen referencia a CFN_NAG siempre que los metadatos de GEM incluyan cfn_nag_rules => true . Para una gema llamada como "CFN-NAG-HIPAA-Rules", se cargará cualquier *.rb bajo lib/cfn-nag-hipaa-reglas. Cualquier regla personalizada debe derivarse de CFNNAG :: Baserule en CFN-NAG/BASE_RULE ( no CFN-NAG/Custom-Rules/Base). Si la regla debe derivar de algo más, definiendo un método cfn_nag_rule? Eso devuelve verdadero también hará que se cargue como regla.
Cuando CFN_NAG se está ejecutando en un AWS Lambda, en realidad no hay un sistema de archivos (además /TMP) en el sentido tradicional. Por lo tanto, solo las reglas centrales se pueden usar de la Lambda. Para admitir reglas personalizadas, CFN_NAG admite descubrir reglas de un cubo S3 en lugar del sistema de archivos.
Todo lo que probablemente haya visto sobre cómo desarrollar reglas personalizadas en Ruby todavía es cierto.
Para descubrir reglas de un cubo S3, cree un archivo s3.yml con este contenido:
---
repo_class_name : S3BucketBasedRuleRepo
repo_arguments :
s3_bucket_name : cfn-nag-rules-my-enterprise
prefix : /rulesPara aplicar *reglas.rb archivos en el bucket cfn-nag-rules-my-enterprise con el prefijo /reglas (eg /rules/mynewrule.rb), especifique este archivo en la línea de comando a cfn_nag como tal:
cat my_cfn_template.yml | cfn_nag --rule-repository s3.yml Si las reglas están en más de un cubo, cree múltiples archivos S3*.yml y especifíquelos en el argumento --rule-repository .
Si las credenciales ambientales de AWS tienen permiso para acceder al bucket cfn-nag-rules-enterprise , entonces encontrará todas las reglas como /rules/*Rule.rb . Si se debe usar un AWS_Profile en particular, agrégalo como una clave en repo_arguments , por ejemplo aws_profile: my_aws_profile
Más allá del sistema de archivos, GEM instala y S3: la nueva arquitectura teóricamente admite el desarrollo de otros "repositorios de reglas" para cargar reglas de DynamodB, bases de datos relacionales u otros servicios web.
Para el autor, nuevas reglas para su propio uso y/o contribución de la comunidad, consulte el desarrollo de reglas personalizadas para más detalles.
Un screencast que demuestra el desarrollo de reglas personalizadas de sopa a nueces TDD está disponible aquí:
https://www.youtube.com/watch?v=JRZCT0NAFD4&t=1601S
Para ejecutar las especificaciones, debe asegurarse de tener Docker instalado y CFN_NAG Dependencias instaladas a través de
gem install bundle
bundle install Luego, para ejecutar todas las especificaciones, simplemente ejecute rake test:all .
Para ejecutar las pruebas de extremo a extremo, ejecute rake test:e2e . El script agrupará todas las gemas en GEMFILE, construirá e instalará la gema CFN_NAG localmente, instalará dependencias de especificaciones y luego ejecuta pruebas etiquetadas con 'End_to_end'. También retirará las plantillas de muestra proporcionadas por Amazon y ejecutará CFN_NAG_SCAN contra ellas, para ver si alguna plantilla conocida causa excepciones dentro de CFN-NAG.
Para instalar la rama Git actual localmente:
bundle install
scripts/deploy_local.shHay un entorno de desarrollo remoto completo creado y configurado con todas las herramientas y configuraciones preconfiguradas para facilitar el desarrollo y la creación de reglas. Puede habilitar esto utilizando la funcionalidad de desarrollo remoto VS Code.
Folder contains a dev container configuration file. Reopen folder to develop in a container Haga clic en el botón Reopen in Container[Dev Container] cfn_nag DevelopmentPuede encontrar más información sobre la configuración de desarrollo remoto de Código VS aquí, el desarrollo remoto del código VS.
Para informar un error o solicitar una función, envíe un problema a través del repositorio de GitHub a través de: https://github.com/stelligent/cfn_nag/issues/new