DevSecOps

27 mar, 2019

Ingestão IAM (AWS) para Neo4j Graph Platform

100 visualizações
Publicidade

Olá, pessoal!

O desafio desta vez consiste em exibir graficamente o que está contido nas configurações do IAM da AWS de maneira amigável.

Vou precisar de uma ferramenta para me ajudar a entender e debater com outras áreas. Criar os modelos manualmente nos faria perder a velocidade na obtenção dos melhores questionamentos.

A ideia principal é extrair os modelos via aws-cli e realizar a ingestão para a ferramenta.

Utilizo Linux e este artigo foi realizado utilizando o Ubuntu 18.04.

Abaixo vou mencionar brevemente sobre cada tecnologia utilizada a fim de esclarecer para alguns ou reforçar o conhecimento para quem tem já sabe.

IAM

Segue a definição da própria AWS:

  • O AWS Identity and Access Management (IAM) permite que você gerencie com segurança o acesso aos serviços e recursos da AWS. Usando o IAM, você pode criar e gerenciar usuários e grupos da AWS e usar permissões para conceder e negar acesso a recursos da AWS.

Trocando em miúdos, é a camada de gerenciamento do usuário AWS, onde criamos o acesso, concedemos o acesso, e criamos as regras de acesso para que cada um dos usuários possuam o acesso de acordo com a própria necessidade.

Segue uma máxima e sempre atual do meu xará William Deming:

  • Não se gerencia o que não se mede, não se mede o que não se define, não se define o que não se entende e não há sucesso no que não se gerencia.

AWS CLI

Utilizaremos o aws-cli para obter as informações provenientes do AWS IAM. Coletaremos de forma programática e realizaremos a carga para dentro do Neo4J.

Para configurar o cliente, siga as instruções deste link.

Feita a configuração vamos realizar o export:

$ aws iam get-account-authorization-details > iam_account.json

Pronto. Se não apareceu nenhuma mensagem de erro, ocorreu tudo com sucesso. A saída é um arquivo json que permite ser inspecionado – faça isso. Aqui eu costumo fazer assim:

$ cat iam_account.json | jq

O jq ajuda a validar o json e mostrará o resultado com sintaxe destacada. Caso não possua em seu sistema operacional, instale-o. Aqui eu faço assim:

$ sudo apt install -y jq

Se conseguiu visualizar o conteúdo, está tudo certo, vamos seguir.

Docker

É necessário que tenha o docker instalado. Siga este passo a passo.

Também será necessário a instalação do docker-compose, veja neste link.

Poderá ser utilizada a imagem oficial do dockerhub, hoje a versão é a 3.5.3.

Construiremos uma imagem e incluiremos o plugin APOC já habilitado – eu mesmo demorei um pouco até entender isso.

As informações existem, mas ainda não estão todas com o passo a passo bem mapeados, então quando a documentação se tornar insuficiente crie sua própria.

Antes disso traremos as dependências. Execute o script “01-dependencias.sh”, que possui a finalidade de criar um diretório e realizar o download neste diretório denominado: plugins.

$ bash 01-dependencias.sh

Ao concluir o script, será listado o arquivo: apoc-3.5.0.2-all.jar.

Para construirmos a nossa própria imagem, utilizaremos o arquivo Dockerfile, então vamos executar o script: 02-construir-imagem-docker.sh e informar como parâmetro o nome da imagem. Nesta POC foi definido o nome: nome-sua-imagem.

$ bash 02-construir-imagem-docker.sh nome-sua-imagem

Não deve apresentar nenhuma mensagem de erro. O resultado obtido será:

REPOSITORY TAG IMAGE ID CREATED SIZE

nome-sua-imagem latest 5cd78ec7247d Less than a second ago 217MB

Agora vamos inicializar através do docker-compose, da seguinte forma:

$ docker-compose up -d

A resposta é isso:

Creating network "neo4j_analytics" with the default driver
Creating neo4j-apoc ...
Creating neo4j-apoc ... done

Através do comando docker ps será possível acompanhar a execução:

$ docker ps  
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                                      NAMES  
01d6df12ef38        nome-sua-imagem     "/sbin/tini -g -- /d…"   46 seconds ago      Up 41 seconds       0.0.0.0:7474->7474/tcp, 7473/tcp, 0.0.0.0:7687->7687/tcp   neo4j-apoc

Contêiner em pé – agora vamos copiar os dados obtidos através do aws-cli, lá para dentro do contêiner.

Vamos copiar o arquivo iam_account.json.

$ docker cp iam_account.json neo4j-apoc:/var/lib/neo4j/import/iam_account.json

Concluída essa parte do Docker.

Neo4J

Aqui é onde acontece a mágica. Segue também a definição do próprio fabricante:

  • Uma plataforma gráfica que revela e persiste as conexões. A plataforma gráfica utiliza uma abordagem de conexões aos dados. Amplia a capacidade de reconhecer a importância de relacionamentos e conexões persistentes em todas as transições da existência: a ideia é projetar em um modelo lógico e implementar em um modelo físico, usando uma linguagem de consulta e persistência dentro de modo escalável e confiável em um sistema de banco de dados. A base da representação dos dados conectados é conhecida como graph.

Agora colocaremos a mão na ferramenta. Até então foi somente a preparação e entendimento do ambiente.

Vá até o browser e digite http://localhost:7474/browser/, você vai se deparar com o primeiro acesso, usuário e senha padrão, sendo: neo4j, neo4j respectivamente.

Após esse passo você informará o usuário e senha definitivos.

RETURN apoc.version();

No canto superior à sua direita há uma seta. Ao posicionar o cursor do mouse, a descrição é play – clique lá.

A versão obtida foi: “3.5.0.2”.

A ferramenta com a interface gráfica funciona dessa maneira, digitar no prompt o comando e clicar em “play”.

O próximo passo é realizar a ingestão dos dados obtidos através do aws-cli. O caminho completo do arquivo dentro do contêiner ficou definido como: /var/lib/neo4j/import/iam_account.json.

Abaixo você confere as queries para realizarmos a ingestão manual através da interface gráfica.

// POLICIES  
CALL apoc.load.json("/var/lib/neo4j/import/iam_account.json",  
'.Policies[*]') YIELD value as row  
MERGE(p:IAM_Policy {id:row.PolicyId, name:row.PolicyName, arn:row.Arn})

// GROUPS  
CALL apoc.load.json("/var/lib/neo4j/import/iam_account.json",  
'.GroupDetailList[*]') YIELD value as row  
MERGE(p:IAM_Group {id:row.GroupId, name:row.GroupName, arn:row.Arn})  

// Load User and relationship to Groups,Policies  
CALL apoc.load.json("/var/lib/neo4j/import/iam_account.json",  
'.UserDetailList[*]') YIELD value as row  
UNWIND row.AttachedManagedPolicies as policy  
UNWIND row.GroupList as group  
CREATE (u:IAM_User {id:row.UserId,name:row.UserName,arn:row.Arn})  
WITH u,policy, group  
MATCH (p:IAM_Policy {name:policy.PolicyName})  
CREATE (u)-[:HAS_POLICY]->(p)  
WITH u,p, group  
MATCH (g:IAM_Group {name:group})  
CREATE (u)-[:MEMBER_OF]->(g)  

// Load Roles and attached Policies to the Roles  
CALL apoc.load.json("/var/lib/neo4j/import/iam_account.json",  
'.RoleDetailList[*]') YIELD value as row  
UNWIND row.AttachedManagedPolicies as policy  
UNWIND policy as pol  
WITH row.RoleName as role, row.Path as path, row.Arn as arn, pol  
MERGE(r:IAM_Role {name:role, path:path, arn:arn})  
MERGE(p:IAM_Policy {name:pol.PolicyName,arn:pol.PolicyArn})  
MERGE(r)-[:HAS_POLICY]->(p)  

// Create relationship btw Groups and Policies  
CALL apoc.load.json("/var/lib/neo4j/import/iam_account.json",  
'.GroupDetailList[*]') YIELD value as row  
UNWIND row.AttachedManagedPolicies as policy  
MATCH (g:IAM_Group {name:row.GroupName})  
MATCH (p:IAM_Policy {name:policy.PolicyName})  
CREATE (g)-[:HAS_POLICY]->(p)  

// Create Policy Actions and relate it to the Policy  
CALL apoc.load.json("/var/lib/neo4j/import/iam_account.json") YIELD value as row  
UNWIND row.Policies as p  
UNWIND p.PolicyVersionList as a  
UNWIND a.Document as d  
UNWIND d.Statement as s  
UNWIND s.Action as act  
WITH p.PolicyName as pol, act as action  
MATCH (p1:IAM_Policy {name:pol})  
MERGE(a1:IAM_Policy_Action {action:action})  
MERGE(p1)-[:HAS_ACTION]->(a1) 

// Create Policy Resources and relate it to the Policy  
CALL apoc.load.json("/var/lib/neo4j/import/iam_account.json") YIELD value as row  
UNWIND row.Policies as p  
UNWIND p.PolicyVersionList as a  
UNWIND a.Document as d  
UNWIND d.Statement as s  
UNWIND s.Resource as res  
WITH p.PolicyName as pol, res as resource  
MATCH (p1:IAM_Policy {name:pol})  
MERGE(r1:IAM_Policy_Resource {name:resource})  
MERGE(p1)-[:HAS_RESOURCE]->(r1)  

// Load Services   
CALL apoc.load.json("/var/lib/neo4j/import/iam_account.json",  
'.RoleDetailList[*]') YIELD value as row  
UNWIND row.AssumeRolePolicyDocument as arpd  
UNWIND arpd.Statement as stmt  
WITH stmt,row.RoleName as role  
WHERE stmt.Effect = 'Allow'   
UNWIND keys(stmt.Principal) AS key  
WITH role,key, stmt.Principal as princ  
WHERE key = 'Service'  
MATCH(r:IAM_Role {name:role})  
CREATE(s:AWS_Service {name: princ[key] })  
CREATE (s)-[:CAN_ASSUME_ROLE]->(r)  

Efetuado a ingestão, para obter o acesso basta ir até o primeiro ícone superior a sua esquerda, com o nome: Database Information. Abaixo será disposta a lista de tags, conforme os carregamentos, contendo as seguintes informações:

  • AWS_Service
  • IAM_Group
  • IAM_Policy
  • IAM_Policy_Action
  • IAM_Policy_Resource
  • IAM_Role
  • IAM_User

Escolher uma das views e selecionar o modo graph – você também poderá utilizar o modo full screen.

Parabéns a você que chegou até aqui!

Projeto

Referências