Compliance como código

AWS User Group São Paulo
awsugsp
Published in
4 min readOct 26, 2017

Quando se tenta implantar boas práticas de segurança e compliance em ambientes cloud, um dos principais problemas é a comunicação. O time de compliance fala a língua das planilhas, o de dev a língua dos códigos e o sec/ops dos comandos e siglas.

Tentando diminuir essa distância a Chef.io (a mesma do software por trás do OpsWorks) criou o Inspec.io com a proposta de automatizar algumas verificações de segurança e em uma linguagem que seja facilmente compreendida por todos os envolvidos: Compliance, dev e sec/ops,

As informações sobre instalação podem ser encontradas aqui. Caso você queira simplesmente baixar os pacotes, pode acessar esse link.

Para automatizar a instalação no seu Amazon Linux (testado com 2017.03.1 HVM, SSD), basta adicionar o código abaixo no seu script de bootstrap, sua instância já vai subir com o inspec instalado.

sudo rpm --import https://packages.chef.io/chef.asccat >chef-stable.repo <<EOL
[chef-stable]
name=chef-stable
baseurl=https://packages.chef.io/repos/yum/stable/el/7/\$basearch/
gpgcheck=1
enabled=1
EOL
sudo yum-config-manager --add-repo chef-stable.reposudo yum install inspec

O que me chamou a atenção para essa solução em primeiro lugar foi a compatibilidade. Você pode fazer uma inspeção local, remota (por SSH ou WInRM) ou em um container docker. Em segundo foi a linguagem de fácil entendimento e o fato dele suportar a checagem de alguns recursos. E por fim o suporte em diversos sistemas operacionais: Linux, BSD, MacOS e Windows.

Vamos criar alguns exemplos para ilustrar a facilidade:

Lógico que todo primeiro exemplo deve ser um Hello World. No nosso caso um Hello Compliance. Então primeiro crie um arquivo chamado hello.txt com o conteúdo “Hello Compliance”. Na mesma pasta crie um arquivo chamado hello.rb com o conteúdo abaixo:

control "hello-compliance-1.0" do
title "Hello Compliance"
desc "Text should include the words 'hello compliance'."
describe file('hello.txt') do
its('content') { should match 'Hello Compliance' }
end
end

Salve e vamos rodar o seguinte comando:

inspec exec hello.rb

O resultado será algo semelhante a isto:

Profile: tests from hello.rbVersion: (not specified)Target: local://✔ hello-compliance-1.0: Hello Compliance✔ File hello.txt content should match "Hello Compliance"Profile Summary: 1 successful control, 0 control failures, 0 controls skippedTest Summary: 1 successful, 0 failures, 0 skipped

Ou seja nosso teste rodou com sucesso.

Vamos dar uma olhada em cada item do nosso código:

control: Este é o nome do controle. Deve ser um nome único.
title: Este é um título que deve ser simples de se entender, para ser lido por pessoas.
desc: Descrição, opcional
describe file(‘hello.txt’): Este é recurso que será testado. O File é um recurso (Resources) que o inspec possui, para abrir arquivos. Poderia ser feito de outra maneira como vamos ver no próximo exemplo.
its(‘content’) { should match ‘Hello Compliance’ }: Agora sim o teste, o conteúdo do arquivo deve conter Hello Compliance.

Percebam que é bem amigável e legível inclusive por pessoas não técnicas.

Em algumas arquiteturas eu costumo usar o EFS que é um compartilhamento de rede gerenciado pela AWS, que escala automaticamente de acordo com a quantidade de espaço que você usa. Então é importante saber se o compartilhamento está montado em cada instância. Neste caso podemos fazer de duas maneiras

A primeira usando o comando ‘mount’:

control "mount-stdout-1.0" do
title "mount stdout"
desc "Verifica se a particao esta montada usando stdout."
describe command('mount') do
its('stdout') { should match /efs/ }
end
end

A segunda usando o recurso mount:

control "mount-resource-1.0" do
title "mount resource"
desc "Verifica se a particao esta montada usando resource."
describe mount('/efs') do
it { should be_mounted }
end
end

Vamos colar os dois conteúdos em um arquivo chamado efs.rb e rodar o comando:

inspec exec efs.rb

Como na sua máquina, provavelmente, não há um compartilhamento efs, você verá um resultado como:

Profile Summary: 0 successful controls, 2 control failures, 0 controls skippedTest Summary: 0 successful, 2 failures, 0 skipped

Entendendo a nossa receita:

describe command(‘mount’): Rodar o comando mount
its(‘stdout’) { should match /efs/ }: Procurar pela regex efs na saída

describe mount(‘/efs’): Olhar o recurso mount, procurar pelo ponto de montagem /efs
it { should be_mounted }: Verificar se está montado

Pela infinidade de recursos você pode fazer configurações em daemons como SSH, neste caso verifica se o PAM está ativo na configuração e a porta do SSH é a 22:

describe sshd_config do
its('Port') { should cmp 22 }
its('UsePAM') { should eq 'yes' }
end

Verifica se o apache está ouvindo na porta 443:

describe apache_conf do
its('Listen') { should eq '443'}
end

Todos os testes que fizemos aqui foram locais, mas temos outros alvos também. No momento podemos usar os seguintes: local, SSH, WinRM e Docker.

Nosso exemplo do efs ficaria assim por SSH:

inspec exec efs.rb -i chave.pem -t ssh://ec2-user@ip_servidor

Caso fosse um container docker:

inspec exec efs.rb -t docker://id_container

Para se aprofundar recomendo o seguinte:

Espero ter ajudado a esclarecer o assunto. Caso tenha alguma dúvida, escreve aqui em baixo. Caso esteja testando, não esqueça de remover os recursos criados.

Originally published at medium.com on September 20, 2017 by Francisco Edilton.

--

--

AWS User Group São Paulo
awsugsp

Comunidade para discussões, palestras e networking de Tecnologias AWS no Brasil e no mundo.