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!