Blog de Amazon Web Services (AWS)

AWS Outposts multi-tenant: networking, aislamiento y gobierno

Por Rafael Hernando Franco Castro | Arquitecto de Soluciones Senior

Compartir un rack de AWS Outposts entre clientes de un operador exige algo más que crear una cuenta por cliente. Una ruta incorrecta puede conectar redes que debían permanecer separadas. Un permiso excesivo puede permitir que alguien cambie esa ruta.

En un modelo de colocation entre empresas, o business-to-business (B2B), el operador necesita administrar infraestructura común. Debe hacerlo sin entregar a cada cliente el control del entorno compartido. Cada tenant debe consumir capacidad y conectar sus aplicaciones con su red local dentro de límites verificables.

Esta arquitectura separa cuatro planos: identidad, recursos, red y datos. El recorrido comienza por networking, continúa con el gobierno mediante AWS Organizations y termina con el despliegue de tenants.

1. Arquitectura de referencia

Figura 1. Outpost multi-tenant con aislamiento de tráfico por CoIP pool. Diagrama fuente: Multitenant_Outposts_Network_Architecture.drawio

Componentes:

  • Data center del operador (dentro del país): aloja el rack Outposts Gen2 y la red on-prem (fabric) a la que se integra cada cliente.
  • Cuenta AWS por cliente: Cliente A y Cliente B tienen cada uno su cuenta, su OU, sus SCPs y su configuración de AWS IAM. Cada cliente despliega su VPC y una subnet de Outpost. En el diagrama ambas VPCs usan 10.10.0.0/16, a propósito.
  • CoIP pool por cliente: 192.168.1.0/24 para A y 192.168.2.0/24 para B. Es la identidad de red del tenant fuera del rack.
  • Local Gateway (LGW) en modo CoIP: tabla de rutas compartida y VIF-Group conectada a la LNI del rack. Aísla el tráfico por CoIP pool aunque los CIDRs de las VPCs se superpongan.
  • Región AWS (us-east-1): contiene las cuentas de Management/Organizations (gobierno, IAM Identity Center, SCPs), Security/Logging (CloudTrail, CloudWatch, Config, VPC Flow Logs) y Backup/DR (snapshots EBS, AWS Backup). AWS RAM comparte el Outpost y las subnets con las cuentas de cliente.
  • AWS Direct Connect privado: transporta el service link entre el Outpost y la región.

2. Capas de aislamiento

Capa Mecanismo Quién lo opera
Gobierno Cuenta por tenant, OU dedicada, SCPs Equipo de plataforma (Management)
Identidad IAM Identity Center, permission sets por tenant, ABAC con tag tenant, permission boundaries Plataforma + tenant
Recursos del Outpost Compartición selectiva con AWS RAM (Outpost, LGW route table, CoIP pool) Cuenta owner
Red en el Outpost VPC por tenant, security groups, NACLs, rutas de subnet Tenant
Borde LGW CoIP pool por tenant, asociación VPC ↔ LGW route table Owner + tenant
Red on-prem VRF/zona de firewall por tenant, filtros BGP Red del operador
Auditoría Organization trail, Flow Logs y Config agregados en Security/Logging Seguridad

El LGW es un recurso único y compartido. Por eso el aislamiento no se resuelve «dentro» del LGW. Depende de tres cosas: qué VPCs están asociadas a su tabla de rutas, qué prefijos CoIP tiene cada tenant y cómo la red on-prem segmenta esos prefijos. Las SCPs y AWS IAM evitan que un tenant cambie cualquiera de esas tres piezas.

3. Modo de la tabla de rutas del LGW: CoIP vs. direct VPC routing

Criterio CoIP Direct VPC routing
IP visible on-prem IP del pool CoIP (NAT 1:1 en el LGW) IP privada de la instancia
CIDRs de VPC solapados entre tenants Permitidos No permitidos
Segmentación on-prem Por prefijo CoIP (se mapea directo a VRF) Por CIDR de VPC
Control del espacio de direcciones El operador asigna los pools Requiere gobierno de los CIDRs de cada cliente
Encaje multi-tenant B2B Alto Medio

Para colocation con clientes externos usamos CoIP. Cada cliente direcciona su VPC como quiera (en la Figura 1, A y B comparten 10.10.0.0/16), y hacia afuera del rack solo existen los prefijos CoIP que asigna el operador.

Advertencia: si un tenant con CIDR solapado también necesita conectividad con otras VPCs en la región (Transit Gateway), el solape se vuelve un problema en la región. Si un cliente lo va a necesitar, reserva un CIDR de VPC único para él desde el principio en el IPAM del operador.

4. Plan de direccionamiento

Tenant VPC CIDR Subnet Outpost CoIP pool VRF on-prem
Cliente A 10.10.0.0/16 10.10.1.0/24 192.168.1.0/24 VRF-A
Cliente B 10.10.0.0/16 (solapado) 10.10.1.0/24 192.168.2.0/24 VRF-B
  • Cada tenant recibe un CoIP pool exclusivo.
  • El tamaño del pool depende de cuántas ENIs deben ser alcanzables desde on-prem (instancias, NVAs, load balancers), no del total de instancias.
  • Los prefijos CoIP se registran en el IPAM del operador y deben ser únicos frente a la red on-prem.

5. Compartir recursos con AWS RAM

La cuenta owner comparte con cada tenant el Outpost, la tabla de rutas del LGW y únicamente el CoIP pool de ese tenant. Usa un resource share por tenant, para poder revocar o auditar a un tenant sin afectar a los demás.

Qué se logra: Cada tenant ve solo los tres recursos del Outpost que necesita (el Outpost, la tabla de rutas del LGW y su propio CoIP pool), ; los pools de los demás tenants quedan fuera de su vista. Con un resource share por tenant se puede auditar o revocar el acceso de un cliente sin tocar a los otros.

aws ram create-resource-share \
   --name outpost-cliente-a \
   --no-allow-external-principals \
   --principals 111111111111 \
   --resource-arns \
      arn:aws:outposts:us-east-1:123456789012:outpost/op-EXAMPLE1234567890 \
      arn:aws:ec2:us-east-1:123456789012:local-gateway-route-table/lgw-rtb-EXAMPLE \
      arn:aws:ec2:us-east-1:123456789012:coip-pool/ipv4pool-coip-CLIENTEA \
   --tags key=tenant,value=cliente-a

--no-allow-external-principals impide compartir con cuentas fuera de la organización. La SCP de la sección 9.6 hace cumplir esa regla en toda la organización.

6. Configuración del plano de datos

Los comandos de esta sección se pueden ejecutar como un solo script. set -euo pipefail detiene la ejecución ante cualquier error o variable vacía, y el bloque inicial verifica que todas las variables requeridas estén definidas antes de tocar el Local Gateway.

#!/usr/bin/env bash
# Variables requeridas:
#   Cuenta owner : LGW_ROUTE_TABLE_ID, TENANT, COIP_CIDR
#   Cuenta tenant: VPC_ID, LGW_ID, ROUTE_TABLE_ID, ONPREM_CIDR, COIP_POOL_ID, ENI_ID
set -euo pipefail

: "${LGW_ROUTE_TABLE_ID:?}" "${TENANT:?}" "${COIP_CIDR:?}"
: "${VPC_ID:?}" "${LGW_ID:?}" "${ROUTE_TABLE_ID:?}" "${ONPREM_CIDR:?}"
: "${ENI_ID:?}"

6.1 CoIP pool y CIDR (cuenta owner)

COIP_POOL_ID=$(aws ec2 create-coip-pool \
   --local-gateway-route-table-id "$LGW_ROUTE_TABLE_ID" \
   --tag-specifications "ResourceType=coip-pool,Tags=[{Key=tenant,Value=$TENANT}]" \
   --query 'CoipPool.PoolId' --output text) 

aws ec2 create-coip-cidr \
   --coip-pool-id "$COIP_POOL_ID" \
   --cidr "$COIP_CIDR"

6.2 Asociar la VPC del tenant a la tabla de rutas del LGW. En el onboarding la ejecuta la plataforma dentro de la cuenta del tenant.

aws ec2 create-local-gateway-route-table-vpc-association \
   --local-gateway-route-table-id "$LGW_ROUTE_TABLE_ID" \
   --vpc-id "$VPC_ID"

6.3 Rutas de la subnet hacia el LGW (cuenta tenant). Se agregan únicamente los prefijos on-prem autorizados para el tenant.

aws ec2 create-route \
  --route-table-id "$ROUTE_TABLE_ID" \
  --destination-cidr-block "$ONPREM_CIDR" \
  --local-gateway-id "$LGW_ID"

6.4 Asignar CoIP a la ENI (cuenta tenant)

ALLOCATION_ID=$(aws ec2 allocate-address --domain vpc \
  --customer-owned-ipv4-pool "$COIP_POOL_ID" \
  --query 'AllocationId' --output text)

aws ec2 associate-address \
  --allocation-id "$ALLOCATION_ID" \
  --network-interface-id "$ENI_ID"</p>

El LGW traduce 1:1 la IP privada de la ENI (10.10.1.10) a la CoIP (192.168.1.10). Por eso las IPs privadas de dos tenants pueden ser idénticas sin generar conflicto fuera del rack.

7. Conectividad on-prem: BGP, VIF-Group y VRFs

El LGW se conecta a los dos network devices del operador a través de la VIF-Group: una VLAN y una sesión eBGP por uplink. Por esas sesiones anuncia todos los prefijos CoIP del Outpost; no hay una sesión BGP por tenant. La separación se hace en la red on-prem:

  • Importación por VRF: cada prefix-list asigna los prefijos CoIP de un tenant a la VRF de ese tenant.
  • Anuncios hacia el LGW: solo los prefijos on-prem que algún tenant necesita. Todo lo que el LGW aprende es visible para todas las VPCs asociadas; el control fino lo dan las rutas de subnet (6.3), los security groups y el firewall.
  • Deny inter-tenant: el tráfico de 192.168.1.0/24 hacia 192.168.2.0/24 sale del rack y vuelve a entrar por la red on-prem. Si el firewall no tiene una regla explícita que lo bloquee, dos tenants del mismo rack pueden alcanzarse entre sí.
  • Redundancia: BGP activo en ambos uplinks, BFD y temporizadores alineados con el SLA, y verificación de que cada prefijo CoIP se aprende por los dos devices.
! Ejemplo conceptual (sintaxis genérica)
  ip prefix-list CLIENTE-A-COIP permit 192.168.1.0/24
  ip prefix-list CLIENTE-B-COIP permit 192.168.2.0/24
  route-map FROM-LGW permit 10
  match ip address prefix-list CLIENTE-A-COIP
  set vrf VRF-A<br />route-map FROM-LGW permit 20
  match ip address prefix-list CLIENTE-B-COIP
  set vrf VRF-B<br />route-map FROM-LGW deny 100

Variante con NVA: si el tenant necesita inspección propia (por ejemplo, un firewall Fortinet dentro de su VPC en el Outpost), sus rutas de subnet apuntan a la ENI del NVA y solo esa ENI recibe CoIP. Todo el tráfico on-prem del tenant pasa por un único punto de control que él mismo administra.

8. Service link y tráfico hacia la región

  • El service link transporta el control plane y el tráfico intra-VPC entre subnets del Outpost y subnets regionales. Es compartido y finito; dimensiónalo con la suma de todos los tenants más la replicación (AWS MGN, AWS Backup).
  • El tráfico hacia on-prem sale siempre por el LGW; el service link queda reservado para el control plane y el tráfico hacia la región. Las SCPs de la sección 9 obligan a que los workloads del tenant corran en el Outpost.
  • Usa AWS Direct Connect privado y monitorea ConnectedStatus y la utilización con las métricas de CloudWatch del Outpost, con alarmas por umbral.

8.1 Capacidad compartida: reservas por tenant

El rack tiene una capacidad física fija, y todos los tenants la comparten. AWS RAM permite compartir Capacity Reservations de un Outpost con otras cuentas de la organización, y el owner no puede modificar las instancias que el tenant lanza dentro de ellas. Para garantizarle a cada tenant la capacidad que contrató, el owner crea On-Demand Capacity Reservations en el Outpost y las comparte con la cuenta del tenant mediante AWS RAM. Las instancias del tenant consumen su reserva y la capacidad restante queda protegida para los demás.

# Cuenta owner: reservar 8 m5.2xlarge en el Outpost para el Cliente A
CR_ARN=$(aws ec2 create-capacity-reservation \
  --instance-type m5.2xlarge \
  --instance-platform Linux/UNIX \
  --availability-zone us-east-1a \
  --outpost-arn arn:aws:outposts:us-east-1:123456789012:outpost/op-EXAMPLE1234567890 \
  --instance-count 8 \
  --instance-match-criteria targeted \
  --tag-specifications 'ResourceType=capacity-reservation,Tags=[{Key=tenant,Value=cliente-a}]' \
  --query 'CapacityReservation.CapacityReservationArn' --output text)

# Agregar la reserva al resource share del tenant
aws ram associate-resource-share \
  --resource-share-arn arn:aws:ram:us-east-1:123456789012:resource-share/EXAMPLE-CLIENTEA \
  --resource-arns "$CR_ARN"

Qué se logra: cada tenant tiene una porción del rack reservada a su nombre. Con –instance-match-criteria targeted, solo las instancias que apuntan explícitamente a la reserva la consumen, de modo que un tenant con exceso de lanzamientos agota su propia reserva y deja intacta la de los demás. La zona de disponibilidad debe ser la del Outpost.

9. Gobierno con SCPs

Organiza las cuentas en OUs: Security (Logging, Backup), Infrastructure (cuenta owner del Outpost) y Tenants (una cuenta por cliente). Las SCPs no otorgan permisos, solo ponen un límite máximo. Todas se aplican a la OU Tenants. Las que bloquean acciones que la plataforma necesita hacer en nombre del tenant (9.1, 9.3, 9.4, 9.5 y 9.7) exceptúan el rol OrgPlatformAdmin.

9.1 Restringir regiones (residencia de datos). Los workloads del tenant solo existen en el Outpost y en su región padre.

Qué se logra: Ninguna cuenta de tenant puede crear recursos ni procesar datos fuera de la región padre del Outpost (us-east-1). Si alguien lanza una instancia, un bucket o una base de datos en otra región, la llamada se rechaza, sin importar los permisos de AWS IAM que tenga. Los servicios globales (AWS IAM, AWS STS, Organizations, Route 53, CloudFront, Support) quedan exceptuados para no romper funciones que no dependen de una región. Con esto se cierra la primera vía de salida de datos del país: la de desplegar en otra región.

{
   "Version": "2012-10-17",
   "Statement": [{ 
         "Sid": "DenyOutsideParentRegion",
         "Effect": "Deny",
         "NotAction": [ 
                 "iam:*", "organizations:*", "sts:*", "sso:*",
                 "support:*", "cloudfront:*", "route53:*", "budgets:*" 
           ], 
          "Resource": "*", 
          "Condition": { 
                 "StringNotEquals": { "aws:RequestedRegion": ["us-east-1"] }, 
                 "ArnNotLike": { "aws:PrincipalArn": "arn:aws:iam::*:role/OrgPlatformAdmin" } 
             }
    }] 
}

9.2 Cómputo y ENIs solo en subnets del Outpost. Sigue el guardrail DenyNotOutpostSubnet que AWS publica para residencia de datos en racks de AWS Outposts: deniega lanzar instancias o crear ENIs en cualquier subnet que no esté en la lista de subnets del Outpost.

Qué se logra: Todo cómputo y toda interfaz de red del tenant tiene que vivir físicamente en el rack. Si alguien intenta lanzar una instancia o crear una ENI en una subnet regional, la llamada se deniega. Esto convierte el requisito regulatorio (los datos de abonados no salen del data center local) en un control técnico que se cumple siempre, en vez de depender de la disciplina del equipo.

{
  "Version": "2012-10-17",
  "Statement": [{
     "Sid": "DenyNotOutpostSubnet",
     "Effect": "Deny",
     "Action": ["ec2:RunInstances", "ec2:CreateNetworkInterface"],
     "Resource": ["arn:aws:ec2:*:*:network-interface/*"],
     "Condition": {
          "ForAllValues:ArnNotEquals": {
               "ec2:Subnet": [
                    "arn:aws:ec2:us-east-1:111111111111:subnet/subnet-CLIENTEA-OP",
                     "arn:aws:ec2:us-east-1:222222222222:subnet/subnet-CLIENTEB-OP"
              ]
           }
    }
  }]
}

La SCP lista ARNs de subnets concretas, así que cada vez que se crea una subnet de Outpost para un tenant hay que actualizarla. Este paso forma parte del checklist de onboarding (sección 14).

9.2.1 Snapshots y copias hacia la región. Se basa en los guardrails DenySnapshotsToRegion, DenySnapshotsNotOutposts y DenyCopyToRegion del mismo artículo de AWS. Si el tenant necesita respaldos en la región (cuenta Backup/DR del diagrama), exceptúa el rol de AWS Backup con ArnNotLike, o no apliques estos guardrails si la regulación permite respaldar en la región.

Qué se logra: Bloquea las rutas indirectas por las que los datos podrían llegar a la región: snapshots de EBS del Outpost guardados en la región, copias o cambios de visibilidad de snapshots, creación y exportación de AMIs, importaciones, tareas de DataSync y escrituras en buckets S3 regionales. Así se cubre el caso de alguien que, sin mover la instancia, copia sus discos o archivos fuera del rack.

{
  "Version": "2012-10-17",
  "Statement": [
      {
        "Sid": "DenySnapshotsToRegion",
        "Effect": "Deny",
        "Action": ["ec2:CreateSnapshot", "ec2:CreateSnapshots"],
        "Resource": "arn:aws:ec2:*::snapshot/*",
        "Condition": {
           "ArnLike": { "ec2:SourceOutpostArn": "arn:aws:outposts:*:*:outpost/*" },
           "Null": { "ec2:OutpostArn": "true" }
         }
      },
     {
       "Sid": "DenySnapshotsNotOutposts",
       "Effect": "Deny",
       "Action": ["ec2:CopySnapshot", "ec2:ModifySnapshotAttribute"],
       "Resource": "arn:aws:ec2:*::snapshot/*",
       "Condition": {
           "ArnLike": { "ec2:OutpostArn": "arn:aws:outposts:*:*:outpost/*" }
         }
      },
     {
       "Sid": "DenyCopyToRegion",
       "Effect": "Deny",
       "Action": [
           "ec2:ModifyImageAttribute", "ec2:CopyImage", "ec2:CreateImage",
            "ec2:CreateInstanceExportTask", "ec2:ExportImage",
            "ec2:ImportImage", "ec2:ImportSnapshot", "ec2:ImportVolume",
            "datasync:Create*", "datasync:Update*"
          ],
         "Resource": "*"
     },
    {
      "Sid": "DenyPutObjectToRegionalBuckets",
      "Effect": "Deny",
      "Action": "s3:PutObject",
      "Resource": "arn:aws:s3:::*"
     }
   ]
}

DenyPutObjectToRegionalBuckets bloquea los buckets S3 regionales (arn:aws:s3:::) y deja disponible S3 on Outposts, que usa el namespace s3-outposts. Ojo: estas SCPs no bloquean logs:PutLogEvents, así que las aplicaciones todavía pueden enviar logs a CloudWatch en la región. Si la regulación lo exige, agrega esa acción al deny.

9.3 Proteger los recursos de borde (LGW y CoIP). Los recursos que llegan por RAM ya no los puede modificar el tenant. Esta SCP agrega una segunda línea de defensa y bloquea que creen o cambien rutas del LGW, pools o asociaciones a VIF.

Qué se logra: Protege el borde de red compartido. Ningún tenant puede crear, borrar ni modificar rutas o tablas del Local Gateway, cambiar su asociación con la VIF-Group ni tocar CoIP pools o sus CIDRs. Con esto un tenant no puede secuestrar el prefijo CoIP de otro, publicar rutas hacia on-prem ni romper la conectividad del rack. Solo el rol de plataforma conserva esos permisos.

{
     "Version": "2012-10-17",
     "Statement": [{
     "Sid": "DenyEdgeNetworkMutation",
     "Effect": "Deny",
     "Action": [
         "ec2:CreateLocalGatewayRoute",
         "ec2:DeleteLocalGatewayRoute",
         "ec2:ModifyLocalGatewayRoute",
         "ec2:CreateLocalGatewayRouteTable",
         "ec2:DeleteLocalGatewayRouteTable",
          "ec2:CreateLocalGatewayRouteTableVirtualInterfaceGroupAssociation",
         "ec2:DeleteLocalGatewayRouteTableVirtualInterfaceGroupAssociation",
         "ec2:CreateCoipPool", "ec2:DeleteCoipPool",
         "ec2:CreateCoipCidr", "ec2:DeleteCoipCidr"
      ],
      "Resource": "*",
      "Condition": {
      "ArnNotLike": { "aws:PrincipalArn": "arn:aws:iam::*:role/OrgPlatformAdmin" }
      }
    }]
}

9.4 Prohibir salidas no controladas. En un modelo de edge soberano, el tenant no debe abrir caminos fuera del LGW.

Qué se logra: Hace que el Local Gateway sea la única salida de red del tenant. Al denegar Internet Gateways, peering, VPN, Transit Gateway, Direct Connect y Global Accelerator, el tenant no puede abrir caminos alternos que se salten el firewall on-prem, la segmentación por VRF o la inspección del operador. Cualquier excepción la crea la plataforma de forma controlada y queda auditada.

{
     "Version": "2012-10-17",
     "Statement": [{
          "Sid": "DenyUncontrolledEgress",
          "Effect": "Deny",
          "Action": [
                  "ec2:CreateInternetGateway", "ec2:AttachInternetGateway",
                  "ec2:CreateEgressOnlyInternetGateway",
                  "ec2:CreateVpcPeeringConnection", "ec2:AcceptVpcPeeringConnection",
                  "ec2:CreateVpnGateway", "ec2:CreateCustomerGateway",
                 "ec2:CreateTransitGatewayVpcAttachment",
                 "directconnect:*", "globalaccelerator:*"
             ],
         "Resource": "*",
          "Condition": {
                 "ArnNotLike": { "aws:PrincipalArn": "arn:aws:iam::*:role/OrgPlatformAdmin" }
           }
     }]
}

Si un tenant necesita conectividad regional por Transit Gateway, la plataforma crea el attachment de forma controlada, fuera del self-service del tenant.

9.5 Proteger el baseline de seguridad y auditoría

Qué se logra: Garantiza que la evidencia de auditoría no se pueda apagar ni borrar desde la cuenta del tenant: CloudTrail, Config, Flow Logs, GuardDuty y Security Hub siguen activos aunque un administrador del tenant tenga permisos amplios. Además impide que la cuenta salga de la organización (y con eso se libre de las SCPs) y elimina los usuarios de AWS IAM con llaves de larga duración, de modo que todo acceso humano usa credenciales temporales de IAM Identity Center.

{
      "Version": "2012-10-17",
      "Statement": [{
       "Sid": "ProtectSecurityBaseline",
       "Effect": "Deny",
        "Action": [
                "cloudtrail:StopLogging", "cloudtrail:DeleteTrail", "cloudtrail:UpdateTrail",
                "config:StopConfigurationRecorder", "config:DeleteConfigurationRecorder",
                "config:DeleteDeliveryChannel",
                "ec2:DeleteFlowLogs",
                "guardduty:DeleteDetector", "guardduty:DisassociateFromAdministratorAccount",
                "securityhub:DisableSecurityHub",
                "organizations:LeaveOrganization",
                "iam:CreateUser", "iam:CreateAccessKey"
          ],
         "Resource": "*",
         "Condition": {
               "ArnNotLike": { "aws:PrincipalArn": "arn:aws:iam::*:role/OrgPlatformAdmin" }
          }
    }]
}

9.5.1 Proteger el rol exento. Las SCPs anteriores exceptúan OrgPlatformAdmin por nombre con ArnNotLike y arn:aws:iam::*:role/OrgPlatformAdmin, así que una sola SCP sirve para toda la OU Tenants. Para que esa excepción sea segura, se necesita un statement adicional que impida al tenant crear, borrar o modificar un rol con ese nombre.

Qué se logra: solo la plataforma puede crear o cambiar el rol que tiene la excepción. Un administrador del tenant que intente crear su propio OrgPlatformAdmin, modificar su trust policy o adjuntarle políticas recibe AccessDenied, de modo que la excepción queda reservada al equipo de plataforma.

{
     "Version": "2012-10-17",
     "Statement": [{
     "Sid": "ProtectPlatformRole",
     "Effect": "Deny",
     "Action": [
           "iam:CreateRole", "iam:DeleteRole", "iam:UpdateRole",
           "iam:UpdateAssumeRolePolicy",
           "iam:PutRolePolicy", "iam:DeleteRolePolicy",
           "iam:AttachRolePolicy", "iam:DetachRolePolicy",
           "iam:PutRolePermissionsBoundary", "iam:DeleteRolePermissionsBoundary",
           "iam:TagRole", "iam:UntagRole"
      ],
     "Resource": "arn:aws:iam::*:role/OrgPlatformAdmin",
     "Condition": {
          "ArnNotLike": {
           "aws:PrincipalArn": "arn:aws:iam::*:role/stacksets-exec-*"
           }
       }
    }]
}

El rol se despliega con StackSets service-managed, por eso el statement exceptúa el rol de ejecución de StackSets. Si usas otra herramienta de despliegue, reemplaza ese ARN por el de su rol.

9.6 Evitar que un tenant re-comparta recursos o los exponga fuera de la organización

Qué se logra: Evita que los recursos compartidos se propaguen sin control. Un tenant no puede volver a compartir con terceros lo que recibió del owner (por ejemplo, la tabla de rutas del LGW) ni aceptar comparticiones de cuentas externas. La única fuente legítima de recursos compartidos es la cuenta owner del operador.

{
     "Version": "2012-10-17",
     "Statement": [
           {
            "Sid": "DenyResharingFromTenants",
             "Effect": "Deny",
             "Action": [
                   "ram:CreateResourceShare", "ram:AssociateResourceShare",
                   "ram:UpdateResourceShare"
             ],
             "Resource": "*"
            },
           {
            "Sid": "DenyShareInvitations",
            "Effect": "Deny",
            "Action": "ram:AcceptResourceShareInvitation",
            "Resource": "*"
          }
     ]
}

Con la compartición de AWS RAM habilitada para la organización, los recursos que comparte el owner llegan a las cuentas de la organización sin invitación. Por eso se puede denegar ram:AcceptResourceShareInvitation, igual que en el guardrail de AWS, y así se bloquean comparticiones que vengan de fuera de la organización.

9.7 Etiquetado obligatorio por tenant (base para ABAC y costos)

Qué se logra: Todo recurso de cómputo, almacenamiento y red queda marcado con su tenant desde que se crea, y esa marca no se puede cambiar después. El tag tenant funciona como identidad del recurso: en él se basan ABAC (sección 10), el chargeback de costos del rack compartido y las reglas de Config que detectan recursos huérfanos o mal asignados.

{
     "Version": "2012-10-17",
     "Statement": [
          {
             "Sid": "RequireTenantTagOnCreate",
             "Effect": "Deny",
             "Action": ["ec2:RunInstances", "ec2:CreateVolume", "ec2:CreateNetworkInterface"],
             "Resource": [
                   "arn:aws:ec2:*:*:instance/*",
                   "arn:aws:ec2:*:*:volume/*",
                   "arn:aws:ec2:*:*:network-interface/*"
              ],
            "Condition": { "Null": { "aws:RequestTag/tenant": "true" } }
          },
          {
           "Sid": "DenyTenantTagTampering",
           "Effect": "Deny",
            "Action": ["ec2:CreateTags", "ec2:DeleteTags"],
            "Resource": "*",
            "Condition": {
                   "ForAnyValue:StringEquals": { "aws:TagKeys": ["tenant"] },
                   "StringNotEquals": { "ec2:CreateAction": ["RunInstances", "CreateVolume", "CreateNetworkInterface"] },
                    "ArnNotLike": { "aws:PrincipalArn": "arn:aws:iam::*:role/OrgPlatformAdmin" }
               }
             }
      ]
}

10. Políticas de AWS IAM por rol

Las SCPs fijan el límite de cada cuenta; AWS IAM define qué hace cada persona dentro de ese límite. Recomendamos tres permission sets de IAM Identity Center por tenant y un rol de red en la cuenta owner. Las sesiones llevan el atributo tenant (por ejemplo, cliente-a) desde el IdP, que se usa como aws:PrincipalTag/tenant para ABAC.

10.1 TenantNetworkAdmin (cuenta del tenant). Administra su VPC y sus rutas hacia el LGW, y asigna CoIP solo desde su pool.

Qué se logra: Le da al equipo de red del tenant autonomía sobre su propia VPC (rutas, security groups, asociación con el LGW y asignación de CoIP) sin que pueda usar el CoIP pool de otro tenant ni modificar recursos que no lleven su tag. El tenant opera su red sin tickets al operador, y el operador mantiene el control del espacio de direcciones.

{
     "Version": "2012-10-17",
     "Statement": [
       {
         "Sid": "ReadOnlyNetwork",
         "Effect": "Allow",
         "Action": ["ec2:Describe*", "ec2:GetCoipPoolUsage", "outposts:Get*", "outposts:List*"],
         "Resource": "*"
        },
       {
        "Sid": "ManageOwnRouteTables",
        "Effect": "Allow",
        "Action": ["ec2:CreateRoute", "ec2:ReplaceRoute", "ec2:DeleteRoute"],
        "Resource": "arn:aws:ec2:us-east-1:111111111111:route-table/*",
        "Condition": {
             "StringEquals": { "ec2:ResourceTag/tenant": "${aws:PrincipalTag/tenant}" }
           }
          },
         {
           "Sid": "AssociateVpcToSharedLgwRtb",
           "Effect": "Allow",
           "Action": [
                   "ec2:CreateLocalGatewayRouteTableVpcAssociation",
                  "ec2:DeleteLocalGatewayRouteTableVpcAssociation"
            ],
           "Resource": [
                   "arn:aws:ec2:us-east-1:123456789012:local-gateway-route-table/lgw-rtb-EXAMPLE",
                   "arn:aws:ec2:us-east-1:111111111111:vpc/*",
                   "arn:aws:ec2:us-east-1:111111111111:local-gateway-route-table-vpc-association/*"
             ]
           },
          {
            "Sid": "CoipFromOwnPoolOnly",
            "Effect": "Allow",
            "Action": "ec2:AllocateAddress",
            "Resource": [
                  "arn:aws:ec2:us-east-1:123456789012:coip-pool/ipv4pool-coip-CLIENTEA",
                  "arn:aws:ec2:us-east-1:111111111111:elastic-ip/*"
              ]
            },
           {
             "Sid": "AssociateCoip",
             "Effect": "Allow",
             "Action": ["ec2:AssociateAddress", "ec2:DisassociateAddress", "ec2:ReleaseAddress"],
             "Resource": "*",
             "Condition": { 
                    "StringEquals": { "aws:ResourceAccount": "111111111111" } }
               },
             {
               "Sid": "ManageOwnSecurityGroups",
               "Effect": "Allow",
               "Action": [
                   "ec2:AuthorizeSecurityGroupIngress", "ec2:AuthorizeSecurityGroupEgress",
                   "ec2:RevokeSecurityGroupIngress", "ec2:RevokeSecurityGroupEgress"
                ],
               "Resource": "arn:aws:ec2:us-east-1:111111111111:security-group/*",
               "Condition": {
                     "StringEquals": { "ec2:ResourceTag/tenant": "${aws:PrincipalTag/tenant}" }
                 }
               }
            ]
}

10.2 TenantWorkloadOperator (cuenta del tenant). Lanza y opera instancias solo en las subnets de Outpost de su tenant, y siempre con el tag tenant correcto.

Qué se logra: Permite que los operadores de aplicación lancen y administren instancias solo en las subnets de Outpost de su tenant, siempre con el tag correcto y sin poder etiquetar recursos existentes. Gracias a ABAC, el mismo permission set sirve para todos los tenants: lo que cambia es el atributo tenant que llega del IdP, no la política.

{
          "Version": "2012-10-17",
          "Statement": [
             {
               "Sid": "LaunchIntoOwnOutpostSubnets",
               "Effect": "Allow",
               "Action": "ec2:RunInstances",
               "Resource": "arn:aws:ec2:us-east-1:111111111111:subnet/*",
               "Condition": {
                      "StringEquals": {
                          "ec2:ResourceTag/tenant": "${aws:PrincipalTag/tenant}",
                          "ec2:ResourceTag/placement": "outpost"
                       }
                  }
              },
             {
               "Sid": "LaunchSupportingResources",
               "Effect": "Allow",
               "Action": "ec2:RunInstances",
               "Resource": [
                        "arn:aws:ec2:us-east-1::image/*",
                        "arn:aws:ec2:us-east-1:111111111111:security-group/*",
                       "arn:aws:ec2:us-east-1:111111111111:key-pair/*",
                       "arn:aws:ec2:us-east-1:111111111111:launch-template/*"
                  ]
               },
              {
                "Sid": "CreatedResourcesMustCarryTenantTag",
                "Effect": "Allow",
                "Action": "ec2:RunInstances",
                "Resource": [
                     "arn:aws:ec2:us-east-1:111111111111:instance/*",
                     "arn:aws:ec2:us-east-1:111111111111:volume/*",
                     "arn:aws:ec2:us-east-1:111111111111:network-interface/*"
                   ],
               "Condition": {
                       "StringEquals": { "aws:RequestTag/tenant": "${aws:PrincipalTag/tenant}" }
                 }
               },
              {
                "Sid": "TagOnLaunchOnly",
                "Effect": "Allow",
                "Action": "ec2:CreateTags",
                "Resource": "*",
                "Condition": { "StringEquals": { "ec2:CreateAction": "RunInstances" } }
               },
              {
               "Sid": "OperateOwnInstances",
              "Effect": "Allow",
              "Action": ["ec2:StartInstances", "ec2:StopInstances", "ec2:RebootInstances",
              "ec2:TerminateInstances", "ssm:StartSession"],
              "Resource": "*",
              "Condition": {
                     "StringEquals": { "aws:ResourceTag/tenant": "${aws:PrincipalTag/tenant}" }
                 }
               },
              {
                "Sid": "ReadOnly",
                "Effect": "Allow",
                "Action": ["ec2:Describe*", "cloudwatch:GetMetricData", "cloudwatch:ListMetrics"],
                "Resource": "*"
               } 
          ]
}

Las subnets de Outpost se identifican con el tag placement=outpost, que pone la plataforma al crearlas. Que realmente estén en el rack lo garantiza la SCP 9.2; esta política solo restringe al operador del tenant a sus propias subnets.

Para el acceso a instancias usamos AWS Systems Manager Session Manager. Así no hace falta abrir SSH ni RDP hacia la red on-prem y cada sesión queda auditada.

10.3 Permission boundary para roles creados por el tenant. Si un tenant crea roles para sus aplicaciones, deben llevar un boundary que no puedan eliminar. Eso le impide escalar privilegios por encima de lo que permite la plataforma.

Qué se logra: Cierra la escalada de privilegios. El administrador del tenant puede crear roles para sus aplicaciones, pero siempre con el boundary TenantBoundary, que no puede quitar ni editar. Aunque a un rol de aplicación le adjunten AdministratorAccess, nunca podrá tocar AWS IAM, AWS RAM, rutas, CoIP, el LGW ni security groups. Además iam:PassRole se limita a roles de app/ y al servicio EC2.

// Política que se adjunta al permission set TenantAdmin
{
     "Version": "2012-10-17",
     "Statement": [
           {
             "Sid": "CreateRolesOnlyWithBoundary",
             "Effect": "Allow",
             "Action": ["iam:CreateRole", "iam:PutRolePermissionsBoundary",
                   "iam:AttachRolePolicy", "iam:PutRolePolicy"],
             "Resource": "arn:aws:iam::111111111111:role/app/*",
             "Condition": {
                    "StringEquals": {
                             "iam:PermissionsBoundary":
"arn:aws:iam::111111111111:policy/TenantBoundary"
                       }
                }
           },
          {
            "Sid": "DenyBoundaryTampering",
             "Effect": "Deny",
             "Action": ["iam:DeleteRolePermissionsBoundary", "iam:CreatePolicyVersion",
                              "iam:DeletePolicy", "iam:SetDefaultPolicyVersion"],
              "Resource": [
                       "arn:aws:iam::111111111111:role/*",
                        "arn:aws:iam::111111111111:policy/TenantBoundary"
                 ]
            },
           {
             "Sid": "PassOnlyAppRoles",
             "Effect": "Allow",
             "Action": "iam:PassRole",
             "Resource": "arn:aws:iam::111111111111:role/app/*",
             "Condition": { "StringEquals": { "iam:PassedToService": "ec2.amazonaws.com" } }
           }
      ]
}

// TenantBoundary: techo para cualquier rol de aplicación
{
          "Version": "2012-10-17",
          "Statement": [
            {
             "Sid": "AppScope",
             "Effect": "Allow",
             "Action": ["s3-outposts:*", "cloudwatch:PutMetricData", "logs:*",
                   "ssm:*", "ssmmessages:*", "kms:Decrypt", "kms:GenerateDataKey"],
             "Resource": "*"
            },
          {
           "Sid": "NoIamNoNetwork",
           "Effect": "Deny",
           "Action": ["iam:*", "organizations:*", "ram:*", "ec2:*Route*", "ec2:*Coip*",
                 "ec2:*LocalGateway*", "ec2:*SecurityGroup*"],
           "Resource": "*"
          }
     ]
}

10.4 OutpostNetworkOps (cuenta owner). Es el único rol que modifica el LGW, los CoIP pools y los resource shares. Exige MFA y pertenencia al equipo de red.

Qué se logra: Concentra en un solo rol de la cuenta owner la capacidad de cambiar el borde de red (LGW, CoIP y resource shares), y solo para miembros del equipo de red autenticados con MFA. Así se separan funciones: quien opera workloads no opera el borde, y cada cambio de red queda atado a una identidad concreta.

{
          "Version": "2012-10-17",
          "Statement": [{
                "Sid": "ManageEdgeNetwork",
                "Effect": "Allow",
                "Action": [
                    "ec2:*LocalGateway*", "ec2:*Coip*",
                    "ram:CreateResourceShare", "ram:AssociateResourceShare",
                    "ram:DisassociateResourceShare", "ram:DeleteResourceShare"
                 ],
               "Resource": "*",
               "Condition": {
                     "StringEquals": { "aws:PrincipalTag/team": "network" },
                     "Bool": { "aws:MultiFactorAuthPresent": "true" }
                  }
           }]
}

11. Políticas basadas en recursos y cifrado

  • AWS KMS por tenant: cada tenant tiene su propia customer managed key para EBS en el Outpost (cifrado por defecto activado en la cuenta). La key policy solo permite principales de la cuenta del tenant y del rol de AWS Backup de la cuenta Backup/DR.
  • Amazon S3 on Outposts: la access point policy limita el acceso a principales de la cuenta del tenant. Si quieres restringir también por red, crea el access point con acceso solo desde la VPC del tenant.

Qué se logra: Aunque un error en AWS IAM le diera permisos a otra cuenta, el access point de S3 on Outposts rechaza cualquier principal que no sea de la cuenta del tenant. Es una defensa del lado del recurso que complementa a IAM y a las SCPs.

{
          "Version": "2012-10-17",
          "Statement": [{
              "Sid": "TenantOnlyAccess",
              "Effect": "Deny",
              "Principal": "*",
              "Action": "s3-outposts:*",
              "Resource": "arn:aws:s3-outposts:us-east-1:111111111111:outpost/op-EXAMPLE1234567890/accesspoint/cliente-a-ap/object/*",
              "Condition": {
                     "StringNotEquals": { "aws:PrincipalAccount": "111111111111" }
               }
      }]
}

12. Detección y auditoría

  • Organization trail en la cuenta Security/Logging, con un bucket inmutable (S3 Object Lock). Ahí quedan registradas todas las llamadas a ec2:*LocalGateway*, ec2:*Coip* y ram:*.
  • VPC Flow Logs obligatorios en cada VPC de tenant y centralizados. Sirven para verificar que no haya tráfico entre 192.168.1.0/24 y 192.168.2.0/24.
  • AWS Config con reglas que marquen subnets fuera del Outpost, ENIs con CoIP de otro pool, recursos sin el tag tenant y security groups abiertos a 0.0.0.0/0.
  • Alarmas de EventBridge ante cambios en la tabla de rutas del LGW, nuevas asociaciones de VPC o resource shares modificados.
  • IAM Access Analyzer para validar cada SCP y política antes de desplegarla y para detectar accesos externos a recursos compartidos.

13. Paso a paso: cómo aplicar las políticas y en qué orden

El orden importa por dos motivos. Si aplicas un deny antes de crear el rol de plataforma exento, puedes dejarte sin acceso. Y si aplicas la SCP de subnets antes de que existan las subnets del Outpost, bloqueas el onboarding. La secuencia que usamos va de afuera hacia adentro: organización, luego cuenta owner, luego cuenta del tenant, luego recursos.

Figura 2. Orden de despliegue de políticas. Las fases 0 a 3 se ejecutan una sola vez; cada tenant nuevo repite las fases 4 y 5.

Fase 0: Preparación (cuenta Management)

  1. Activar todas las funcionalidades de AWS Organizations y los tipos de política SCP: aws organizations enable-policy-type –root-id r-xxxx –policy-type SERVICE_CONTROL_POLICY.
  2. Crear la estructura de OUs: Security, Infrastructure y Tenants. Crear también una OU Sandbox para probar.
  3. Activar la compartición de AWS RAM con la organización (aws ram enable-sharing-with-aws-organization). Sin esto, la SCP 9.6 bloquearía la llegada de los shares del owner.
  4. Crear en todas las cuentas el rol OrgPlatformAdmin (con StackSets service-managed sobre la raíz de la organización). Tiene que existir antes de cualquier deny que lo exceptúe.
  5. Configurar IAM Identity Center con el IdP y propagar los atributos tenant y team como atributos de sesión (Attributes for access control).

Fase 1: Auditoría y detección primero (cuentas Security/Logging)

  1. Crear el organization trail de CloudTrail hacia el bucket con Object Lock en la cuenta Logging.
  2. Activar AWS Config agregado, GuardDuty y Security Hub con administrador delegado en la cuenta Security.
  3. Aplicar la SCP 9.5 (ProtectSecurityBaseline) a la raíz o a la OU Tenants. Va primero para que todo lo que sigue quede auditado y no se pueda apagar la evidencia.

Fase 2: Guardrails de la OU Tenants (sin impacto en el borde todavía)

  1. Validar cada SCP con IAM Access Analyzer: aws accessanalyzer validate-policy –policy-type SERVICE_CONTROL_POLICY –policy-document file://scp.json.
  2. Adjuntar las SCPs a la OU Sandbox y probarlas con una cuenta de prueba (ver la fase 5).
  3. Pasarlas a la OU Tenants en este orden, de menor a mayor impacto: 9.1 Regiones, 9.6 RAM, 9.5 si no se aplicó en la raíz, 9.4 Egress, 9.3 Borde LGW/CoIP y 9.7 Tags.
  4. Dejar 9.2 (subnets) y 9.2.1 (snapshots y copias) para la fase 4, porque necesitan los ARNs reales de las subnets del Outpost y la decisión sobre respaldos regionales.
  5. Tener en cuenta las cuotas de SCPs: hoy AWS publica un máximo de 10 SCPs adjuntas directamente por raíz, OU o cuenta (las heredadas no cuentan), y cada documento admite hasta 10.240 caracteres. Antes este límite era de 5 por OU, y parte de la guía de Control Tower todavía lo menciona, así que confírmalo en Service Quotas. Si usas AWS Control Tower, sus controles preventivos también ocupan cupo. Igual conviene agrupar declaraciones (por ejemplo 9.3 + 9.4 en «Tenant-Network-Guardrails» y 9.5 + 9.6 en «Tenant-Baseline-Guardrails»). Si guardas la política con la CLI, los espacios cuentan como caracteres; minifica el JSON.
       aws organizations create-policy --type SERVICE_CONTROL_POLICY \
             --name Tenant-Network-Guardrails --description "9.3 + 9.4" \
             --content file://tenant-network-guardrails.json

       aws organizations attach-policy \
             --policy-id p-EXAMPLE --target-id ou-xxxx-tenants

        

Fase 3: Cuenta owner del Outpost (OU Infrastructure)

  1. Crear el rol OutpostNetworkOps (10.4) con su condición de MFA y team=network.
  2. Crear la tabla de rutas del LGW en modo CoIP, asociarla a la VIF-Group y configurar BGP con los routers on-prem (sección 7).
  3. Crear el CoIP pool del tenant y su CIDR (6.1).
  4. Crear el resource share dedicado del tenant (sección 5).

Fase 4: Onboarding de cada tenant

  1. Crear la cuenta en la OU Tenants. Las SCPs ya aplicadas se heredan al instante.
  2. Crear la política TenantBoundary (10.3) en la cuenta, con StackSets. Tiene que existir antes que el permission set TenantAdmin que la exige.
  3. Asignar los permission sets TenantAdmin (10.3), TenantNetworkAdmin (10.1) y TenantWorkloadOperator (10.2) a los grupos del tenant.
  4. La plataforma (OrgPlatformAdmin) crea la VPC y la subnet de Outpost con los tags tenant y placement=outpost, y la asocia a la tabla de rutas del LGW (6.2).
  5. Actualizar la SCP 9.2 con el ARN de la subnet nueva (aws organizations update-policy) y, si aplica, adjuntar 9.2.1.
  6. Crear la customer managed key de KMS del tenant, activar el cifrado EBS por defecto y aplicar la policy del access point S3 on Outposts (sección 11).
  7. Entregar el acceso al tenant. A partir de aquí opera dentro de los límites definidos.

Fase 5: Validación negativa (probar que lo prohibido falla)

Con un rol del tenant, cada uno de estos comandos debe devolver AccessDenied o UnauthorizedOperation. Si alguno funciona, hay un hueco en la política.

# 9.1 – lanzar en otra región

aws ec2 run-instances --region us-west-2 ... --dry-run

# 9.2 – lanzar en una subnet regional

aws ec2 run-instances --subnet-id subnet-REGIONAL ... --dry-run

# 9.3 – tocar el borde

aws ec2 create-local-gateway-route --local-gateway-route-table-id lgw-rtb-EXAMPLE \
--destination-cidr-block 0.0.0.0/0 --local-gateway-virtual-interface-group-id lgw-vif-grp-EXAMPLE

# 9.4 – abrir salida a internet

aws ec2 create-internet-gateway

# 9.5 – apagar auditoría

aws cloudtrail stop-logging --name org-trail

# 10.1 – usar el CoIP pool de otro tenant

aws ec2 allocate-address --domain vpc --customer-owned-ipv4-pool ipv4pool-coip-CLIENTEB

# 10.3 – quitar el boundary

aws iam delete-role-permissions-boundary --role-name app/mi-app

Verificación del estado del borde. Estos comandos confirman que las rutas del LGW, el uso de los pools y el registro de auditoría coinciden con el diseño. Los dos primeros se ejecutan en la cuenta owner. La consulta de CloudTrail se ejecuta en la cuenta del tenant, porque CreateRoute sobre sus route tables queda registrado en esa cuenta; para verlo desde un solo lugar, consulta el organization trail en la cuenta Security/Logging.

# Rutas del LGW: solo deben aparecer los prefijos on-prem autorizados
   aws ec2 search-local-gateway-routes \
      --local-gateway-route-table-id lgw-rtb-EXAMPLE \
      --filters Name=type,Values=static,propagated \
      --query 'Routes[].[DestinationCidrBlock,Type,State]' --output table
# Salida esperada: 172.16.10.0/24 | propagated | active (sin 0.0.0.0/0 inesperadas)

# Uso del pool CoIP del tenant: cada IP asignada corresponde a una ENI del tenant
   aws ec2 get-coip-pool-usage \
      --pool-id ipv4pool-coip-CLIENTEA \
      --query 'CoipAddressUsages[].[CoIp,AwsAccountId,AllocationId]' --output table
# Salida esperada: cada IP asignada muestra AwsAccountId = 111111111111 (cuenta del Cliente A);
# las IPs libres aparecen solo con CoIp, sin AllocationId ni AwsAccountId

# Auditoría (cuenta del tenant): cambios de rutas en las últimas 24 h
# date -d es GNU (Linux/CloudShell); en macOS usa: date -u -v-1d +%Y-%m-%dT%H:%M:%SZ
    aws cloudtrail lookup-events \
       --lookup-attributes AttributeKey=EventName,AttributeValue=CreateRoute \
       --start-time "$(date -u -d '-1 day' +%Y-%m-%dT%H:%M:%SZ)" \
       --query 'Events[].[EventTime,Username,CloudTrailEvent]' --output text

# Salida esperada: solo eventos de roles TenantNetworkAdmin u OrgPlatformAdmin
Prueba Cómo ejecutarla Resultado esperado
Región no permitida (9.1) run-instances –region us-west-2 –dry-run con rol del tenant UnauthorizedOperation
Subnet regional (9.2) run-instances –subnet-id subnet-REGIONAL –dry-run UnauthorizedOperation
Borde LGW (9.3) create-local-gateway-route con rol del tenant AccessDenied
Pool ajeno (10.1) allocate-address –customer-owned-ipv4-pool del otro tenant UnauthorizedOperation
Uso del pool get-coip-pool-usage por pool Solo IPs de la cuenta dueña del pool
Rutas del LGW search-local-gateway-routes Solo prefijos autorizados, estado active
Auditoría cloudtrail lookup-events EventName=CreateRoute Solo roles autorizados
Aislamiento de red ping/traceroute desde VRF-A a CoIP de A y de B A responde; B no responde

Completa la validación de red: desde la VRF-A, ping/traceroute a la CoIP de A tiene que responder y a la CoIP de B tiene que fallar. Además revisa en Flow Logs que no haya flujos entre 192.168.1.0/24 y 192.168.2.0/24.

Fase 6: Operación continua

  1. Gestionar las políticas como código (CloudFormation/StackSets o Terraform) con revisión por pares. Ningún cambio se hace en consola.
  2. Pipeline: aws accessanalyzer validate-policy –policy-type SERVICE_CONTROL_POLICY (o IDENTITY_POLICY / RESOURCE_POLICY según el caso), luego despliegue a Sandbox, luego la validación negativa de la fase 5, luego despliegue a Tenants.
  3. Alarmas de EventBridge ante AttachPolicy/DetachPolicy/UpdatePolicy en Organizations y ante cambios en el LGW o en RAM.
  4. Revisión trimestral con IAM Access Analyzer (accesos sin usar y accesos externos) y de la lista de subnets de la SCP 9.2.

14. Checklist de onboarding de un tenant

  1. Crear la cuenta en la OU Tenants (las SCPs de la sección 9 se heredan automáticamente).
  2. Configurar los permission sets TenantNetworkAdmin, TenantWorkloadOperator y TenantAdmin con el atributo tenant.
  3. Reservar el prefijo CoIP (y el CIDR de VPC si va a tener conectividad regional) en el IPAM del operador.
  4. Crear el CoIP pool y asignarle el CIDR; crear el resource share RAM dedicado (Outpost + LGW route table + CoIP pool).
  5. Crear la customer managed key de KMS del tenant y activar el cifrado EBS por defecto.
  6. Asociar la VPC a la LGW route table; crear la subnet de Outpost con rutas solo hacia los prefijos on-prem autorizados.
  7. Agregar el ARN de la subnet de Outpost del tenant a la SCP DenyNotOutpostSubnet (9.2).
  8. Configurar la prefix-list, la VRF y la regla deny inter-tenant en los routers y el firewall.
  9. Activar Flow Logs y verificar que las reglas de Config estén en estado compliant.
  10. Prueba de aislamiento: la ENI con CoIP debe ser alcanzable desde la VRF del tenant y no alcanzable desde las demás VRFs ni desde otras cuentas.
  11. Validar la capacidad del rack y actualizar el presupuesto de throughput del service link.

15. Resumen y cierre

Qué se logró

Un solo rack de AWS Outposts quedó dividido entre varios clientes. Cada uno tiene aislamiento verificable en identidad, recursos, red y datos, y todos sus datos permanecen en el data center local, dentro del país.

  • Aislamiento de red sin coordinar direccionamiento: cada cliente usa el CIDR de VPC que quiera, incluso uno solapado con el de otro tenant. Fuera del rack, cada tenant solo existe como su propio prefijo CoIP.
  • Segmentación de extremo a extremo: un tenant se corresponde con una cuenta AWS, un CoIP pool y una VRF on-prem. La relación es 1:1 en todos los niveles, así que es fácil de operar y de auditar.
  • Residencia de datos como control técnico: el cómputo, los volúmenes, los snapshots y los objetos solo pueden existir en el Outpost. El cumplimiento no depende de la disciplina del equipo.
  • Autonomía del tenant con un borde protegido: cada cliente administra su VPC, sus rutas, sus security groups y sus instancias. Solo el operador puede modificar el Local Gateway, los CoIP pools y los resource shares.
  • Gobierno escalable: las mismas SCPs y los mismos permission sets sirven para todos los tenants gracias a ABAC. Para sumar un cliente se repiten las fases 4 y 5, sin rediseñar nada.
  • Evidencia inmutable: toda acción sobre el borde de red, las políticas o los datos queda registrada en una cuenta de seguridad que los tenants no pueden alterar.

Cómo se logró

Objetivo Mecanismo principal Secciones
Aislar tráfico entre tenants LGW en modo CoIP, un pool por tenant, VRF y deny inter-tenant on-prem 4, 6, 7
Compartir el rack sin exponer recursos ajenos Un resource share de AWS RAM por tenant 5
Mantener los datos en el país SCPs de región, de subnets del Outpost, de snapshots y de copias 9.1, 9.2, 9.2.1
Proteger el borde compartido SCPs de LGW/CoIP y de egress, más el rol OutpostNetworkOps con MFA 9.3, 9.4, 10.4
Evitar la escalada de privilegios Permission boundary y PassRole restringido 10.3
Atribuir cada recurso a un tenant Tag tenant obligatorio e inmutable, con ABAC 9.7, 10.1, 10.2
Garantizar la auditoría Organization trail con Object Lock, Config, Flow Logs y SCP de baseline 9.5, 12
Desplegar sin romper nada Orden por fases, Sandbox y validación negativa 13

Lecciones clave

  • El Local Gateway es compartido. El aislamiento se diseña alrededor de él: con las asociaciones de VPC, los CoIP pools y la segmentación on-prem.
  • La red on-prem es parte de la arquitectura multi-tenant. Sin VRFs y sin una regla explícita que bloquee el tráfico entre tenants, dos clientes del mismo rack pueden alcanzarse por sus CoIP.
  • Las SCPs ponen el límite y AWS IAM reparte los permisos dentro de ese límite. Se necesitan las dos capas: SCPs para lo que nadie debe hacer y políticas de AWS IAM para lo que cada rol sí puede hacer.
  • El orden de despliegue es parte del diseño. Crear el rol exento antes de cualquier deny y probar en Sandbox antes de aplicar en Tenants evita bloqueos en producción.
  • Hay que probar lo que debe fallar. La validación negativa es la única forma de demostrar que el aislamiento existe.

Trade-offs de diseño

Dos decisiones de este diseño cambian control por simplicidad de operación, y conviene tomarlas a propósito:

  • Tag obligatorio en ENIs (SCP 9.7): exigir el tag tenant en ec2:CreateNetworkInterface hace que hasta la última interfaz de red quede atribuida a un tenant. El costo es que algunos servicios crean ENIs en nombre del tenant (load balancers, endpoints, NVAs con automatización propia) y pueden no pasar el tag, así que la SCP los bloquearía. Hay dos salidas: exceptuar los service-linked roles de esos servicios con aws:PrincipalArn, o dejar el tag obligatorio solo para instancias y volúmenes y detectar las ENIs sin tag con una regla de AWS Config. La primera da más control preventivo; la segunda, menos fricción operativa.
  • Una sola SCP con las subnets de todos los tenants (SCP 9.2): un documento central con todos los ARNs de subnets del Outpost es fácil de auditar y se mantiene en un solo lugar. El costo es que crece con cada tenant y se acerca al límite de tamaño de una SCP (10.240 caracteres). Además, un error al editarla afecta a todos los tenants a la vez. La alternativa es una SCP por tenant adjunta directamente a su cuenta, con solo sus subnets: aísla el impacto de cada cambio y escala sin límite práctico, a cambio de más documentos que gestionar (y del cupo de SCPs por cuenta). Una regla práctica es empezar con la SCP central y migrar a SCP por cuenta cuando el documento supere la mitad del límite o cuando el rack pase de un puñado de tenants.

Conclusion

AWS Outposts lleva la infraestructura, las APIs y las herramientas de AWS al data center local. Con el diseño correcto, también puede funcionar como plataforma multi-tenant para operadores que ofrecen servicios a sus propios clientes. La clave no está en una sola función, sino en combinar capas: CoIP y VRFs para la red, AWS RAM para compartir, SCPs para los límites, AWS IAM y ABAC para la autonomía, y auditoría centralizada para la evidencia.

Si estás evaluando un modelo de colocation sobre Outposts, empieza por el plan de direccionamiento CoIP y la segmentación on-prem. Después define las SCPs en una OU de prueba y automatiza el onboarding por tenant desde el primer día. Así, sumar un cliente nuevo al rack es repetir un proceso conocido, sin nuevas decisiones de arquitectura.

Referencias

Acerca del Autor

Rafael Hernando Franco Castro es Arquitecto de Soluciones en Amazon Web Services (AWS), donde ayuda a operadores de telecomunicaciones y clientes empresariales en Latinoamérica a diseñar e implementar arquitecturas de nube híbrida y edge. Su trabajo abarca tecnologías de analítica y datos, contenerización, SaaS y aplicaciones de GenAI . Ha acompañado a clientes en Colombia, Ecuador, Bolivia, Peru,El Caribe y Centroamérica, en múltiples industrias, a construir con los servicios de AWS. Puedes conectar con Rafael en LinkedIn.