En proyectos pasados y actuales he tenido que lidiar con los servicios cloud de Amazon, los conocidos como Amazon Web Services. Para los que no los conozcan, son un conjunto de servicios de computación, almacenamiento, base de datos, redes, análisis… que permiten montar infraestructuras complejas, eficientes y escalablas a precios muy competitivos (se paga por uso).
En un principio me tocó montar la red, servidores, servicios y bases de datos. Ahora ando desde otro punto de vista, el de tratar de asegurar la infraestructura para que la continuidad de negocio de mi trabajo actual no se vea comprometida. La puerta de entrada son los usuarios y de eso vamos a hablar hoy.
Entendiendo Amazon WS IAM
Para gestionar el acceso a los recursos, AWS cuenta con un servicio llamada IAM (Identity & Access Management) que permite gestionar el acceso a los recursos en base a diferentes identidades:
Usuarios: es una entidad individual, una persona que utiliza recursos. Cuando creamos un usuario, le podemos dar acceso a la consola de administración o a la api para que pueda interactuar con aquello que deseemos de AWS mediante políticas de uso.
Grupos: se utilizan para agrupar usuarios que tienen características similares y, por tanto, permisos similares. Normalmente se usan para crear departamentos en los que todos los usuarios tienen que tener acceso a los mismo recursos. Editar, añadir o eliminar una política al grupo, afecta inmediatamente a todos los usuarios del mismo.
Roles: son parecidos a los usuarios, pero de forma inpersonal. Son permisos que se conceden para llevar a cabo determinadas tareas puntuales. Se suelen usar para asignar a máquinas o procesos que se lanzan de forma automática o incluso aquellas que se lanzan de forma manual sin importar el usuario que lo hace (no es el usuario el que tiene los premisos, es el popio proceso).
¿Cómo indico qué se puede o no hacer?
Para eso están las policies, que son reglas que se aplican para cada servicio y que pueden contener todo tipo de detalle para hacerlas completamente a medida. Una policy tiene un aspecto similar a esto:
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": "ec2:Describe*",
"Resource": "*"
}
]
}
Tener cierto control y destreza a la hora de escribir estas policies es complicado, por eso Amazon nos pone a mano dos recursos interesantes:
- AWS Policy Generator: una web en la que podemos ver todas las opciones que hay para cada servicio e incluso generar el fichero para hacer copy-paste.
Web para generar policies de AWS.
- Herramienta interna de simulación: desde la consola de administración de IAM podemos hacer una simulación de la policy que realizará una prueba sobre los recursos y acciones que definamos.
Enlace para simular policy concreta
Pantalla del simulador de policies
Asignación de policies
A la hora de aplicarlas sobre un usuario o grupo, podemos optar por hacerlo de dos formas:
- Managed: podemos verlo como un policies que tenemos almacenadas y que asignamos con intención de que sea algo permanente (aunque, por supuesto, podemos revocar en cualquier momento).
- Inline: es algo así como permisos temporales que se asignan con la intención de que sea algo puntual, ya sea por la persona o grupo que lo recibe o por el tipo de permiso que se concede.
¿Vemos un ejemplo?
Con todo esto, una posible situación sería asignar grupos por departamento y entorno de desarrollo, asignando las policies necesarias para cada zona concreta. Por ejemplo:
- Departamento1-DEV: policies para usuarios del departamento1 con acceso a recursos de desarrollo.
- Departamento1-PRE: policies para usuarios del departamento1 con acceso a recursos de preproducción.
- Departamento1-PRO: policies para usuarios del departamento1 con acceso a recursos de producción.
Puesto que un usuario puede pertenecer a varios grupos, no habría problema en asignar a «Usuario1» a los grupos «DEV» y «PRE» del «Departamento1».
Control casero
Cuando todo esto empieza a crecer, utilizo un pequeño script que me lista todos los usuarios, así como las políticas que tiene asignadas como grupo o individualmente. Me sirve para exportar rápidamente esa información y poder ver en papel la foto actual de los permisos. Si utilizas la consola, tienes que entrar uno a uno y es un poco coñazo.
Lo único que hago es tirar consultas sobre la API para mostrar, de forma ordenada, la información que necesito.
##########################################################################################
#
# File: iam-list-users-policies.py
# Author: Cristobal Espinosa
#
# https://boto3.readthedocs.org/en/latest/reference/services/index.html
#
##########################################################################################
# Imports ################################################################################
import boto3
from colorama import init, Fore, Style
##########################################################################################
# Initial values #########################################################################
init(autoreset=True)
step = False # Set as True to step by step view
##########################################################################################
print
print Fore.GREEN + '-- IAM POLICIES CONTROL'
print Fore.GREEN + '----------------------------------------------------------------------------------'
print
client = boto3.client('iam')
user_list = client.list_users()
# List users
for user in user_list['Users']:
print Fore.YELLOW + '[**] ' + Fore.WHITE + user['UserName'] + ':'
# List user inline policies
print Fore.YELLOW + '\t[*] ' + Fore.WHITE + 'User inline policies:'
user_policies = client.list_user_policies(UserName = user['UserName'])
for policy in user_policies['PolicyNames']:
print '\t\t- ' + policy
print
# List user managed policies
print Fore.YELLOW + '\t[*] ' + Fore.WHITE + 'User managed policies:'
user_policies = client.list_attached_user_policies(UserName = user['UserName'])
for policy in user_policies['AttachedPolicies']:
print '\t\t- ' + policy['PolicyName']
print
# Get user groups
user_groups = client.list_groups_for_user(UserName = user['UserName'])
print Fore.YELLOW + '\t[*] ' + Fore.WHITE + 'User groups and associated policies:'
for group in user_groups['Groups']:
group_policies = client.list_attached_group_policies(GroupName = group['GroupName'])
for group_policy in group_policies['AttachedPolicies']:
print '\t\t- [' + group['GroupName'] + '] -> ' + group_policy['PolicyName']
print
print Fore.GREEN + '----------------------------------------------------------------------------------'
print
if step:
raw_input("Press Enter to continue...")
print
Me gustaría trabajar en ampliar este script para que sea capaz de avisarme de cambios tanto en policies como en el contenido de las mismas, de forma que si un usuario «obtiene cambios fuera de control», pueda enterarme lo antes posible.
El resultado de este código es algo así:
Resultados del primer usuario
Lo que podéis ver aquí es el modo paso a paso (step = True) con los resultados del primer usuario (el nombre es lo que hay borrado junto a [**]). Se ve rápidamente que no tiene policies de tipo inline o managed y que, todo lo que tiene, le llega por pertenecer a dos grupos del mismo departamento y diferente entorno (DEV y PRE). Las policies asociadas a cada grupo aparecen a la derecha del mismo.
Como véis, un script muy sencillo, pero que me permite exportar rápidamente la información que necesito para verificar si algún usuario tiene permisos que no debe o pertenece a algún grupo equivocado.
De momento, esto es todo, en la continuación de esta entrada hablaremos del usuario root y de la autenticación con segundo factor. Espero que os esté resultando interesante y, como siempre digo, si ves algún error, no estás de acuerdo con lo que cuento o quieres hacer alguna aportación, no dudes en pasarte por los comentarios.