Dormeto
ENFR

Prise en main

Accès à l'organisation

Pour lire vos équilibreurs de charge et installer ses routeurs, le manager Dormeto assume deux rôles dans chaque compte. Pour lister vos comptes, il utilise une politique de délégation de votre compte de gestion. Dormeto ne crée jamais ces éléments lui-même : vous les créez avec Terraform, l'AWS CLI ou un StackSet à vous. Le manager les vérifie à chaque exécution de la découverte.

19 min de lectureManager 0.21.0

Ressources nécessaires

OùÉlémentCe qu'il permetSans cela
Le compte de gestionLa politique de délégationLe rôle de découverte du manager liste les comptes, les unités d'organisation et les tags des comptes (lecture seule).Le mode organisation est indisponible.
Chaque compte à découvrirDmtDiscoveryRoleLecture seule : équilibreurs de charge, listeners, règles, target groups et leur état de santé, groupes Auto Scaling, services ECS. Aussi les clusters EKS et les instances derrière un target group, et les métriques de requêtes. Les nœuds d'un cluster ne sont jamais mis en veille. Aussi les paramètres des trails CloudTrail (rafraîchissement sur événement) et les tags de son propre rôle. Elle peut aussi invoquer les fonctions proxy des clusters privés, avec son propre jeton en lecture seule.Le compte n'est pas analysé.
Chaque compte où des workloads sont mis en veilleDmtCommandRole et la politique DmtRouterBoundaryInstalle, met à jour et supprime les routeurs par appels d'API, uniquement dans leur propre espace de noms. Ce sont les fonctions, tables, files et règles dmtr-*, et les rôles sous /dormeto/router/ soumis à cette limite d'autorisations. Avec le rafraîchissement sur événement, gère aussi un relais. C'est un rôle et une règle par région, qui transmettent au manager les modifications des équilibreurs de charge. Gère les access entries des routeurs dans les clusters EKS du compte. Pour les clusters privés, gère une fonction proxy dans le VPC du cluster avec une règle TCP 443 sur le groupe de sécurité du cluster. Ne touche à rien d'autre.L'intégration et l'installation des routeurs sont refusées, et le rafraîchissement sur événement est indisponible.
Chaque cluster EKS dont des workloads sont mis en veilleLes droits du groupe dormeto:routerLes routeurs lisent les workloads et les mettent à l'échelle. Ils ne créent, ne modifient et ne suppriment que leurs propres Ingresses (Kubernetes).Les workloads du cluster ne peuvent pas être intégrés (motif indiqué).

Ces rôles ne font confiance qu'aux rôles du manager, désignés par leur nom dans le compte du manager. Ce sont son rôle de découverte (dmt-<env>-manager-discovery) et son rôle d'opérations (dmt-<env>-manager-operations). Le rôle de découverte n'est accepté que depuis votre organisation si vous renseignez organization_id dans le module. Vous pouvez les créer avant le manager, et ils restent valides après une réinstallation de celui-ci. Plusieurs managers (par exemple production et staging) partagent les rôles d'un compte : indiquez chaque environnement dans envs. Les rôles du compte du manager sont créés par le module du manager. Pour utiliser d'autres noms que DmtDiscoveryRole et DmtCommandRole, définissez-les dans le Terraform du manager (discovery_role_name, command_role_name) et dans le module d'accès. Le manager n'assume jamais aucun autre rôle, pas même un rôle d'administrateur, sauf si vous le désignez à ces endroits. Comment le manager utilise le rôle de commande, et comment apporter le vôtre : Comment le manager installe les routeurs.

Avec Terraform

Chaque version publie deux modules en plus de celui du manager. Remplacez 111122223333 par l'ID du compte du manager, prod par son environnement (ou par une liste d'environnements) et o-exampleorgid par l'ID de votre organisation.

Dans le compte de gestion

Une seule politique par organisation

Une organisation ne possède qu'une seule politique de délégation, et ce module la réécrit entièrement. Vérifiez d'abord si la vôtre en a déjà une (aws organizations describe-resource-policy). Si c'est le cas, copiez ses autres déclarations dans additional_statements. Ou suivez la procédure AWS CLI ci-dessous, qui les fusionne.

module "dormeto_organization" {
  source             = "https://releases.dormeto.com/manager/0.21.0/dormeto-organization-0.21.0.zip"
  manager_account_id = "111122223333"
  envs               = ["prod"]
  # additional_statements = [ … the policy's other statements … ]
}

Dans chaque compte membre

Déclarez un provider et une instance du module par compte, avec des droits d'administrateur sur ce compte. Par exemple, au moyen d'un rôle que vous utilisez déjà pour l'administrer. Exemple avec deux comptes, shop et data :

provider "aws" {
  alias  = "shop"
  region = "us-east-1"
  assume_role {
    role_arn = "arn:aws:iam::222233334444:role/YourAdministrationRole"
  }
}

provider "aws" {
  alias  = "data"
  region = "us-east-1"
  assume_role {
    role_arn = "arn:aws:iam::555566667777:role/YourAdministrationRole"
  }
}

module "dormeto_access_shop" {
  source             = "https://releases.dormeto.com/manager/0.21.0/dormeto-access-0.21.0.zip"
  providers          = { aws = aws.shop }
  manager_account_id = "111122223333"
  envs               = ["prod"]
  organization_id    = "o-exampleorgid"
}

module "dormeto_access_data" {
  source              = "https://releases.dormeto.com/manager/0.21.0/dormeto-access-0.21.0.zip"
  providers           = { aws = aws.data }
  manager_account_id  = "111122223333"
  envs                = ["prod"]
  organization_id     = "o-exampleorgid"
  create_command_role = false # discovered, never napped
}

Pour un compte dont les workloads sont découverts mais jamais mis en veille, définissez create_command_role = false, comme pour data ci-dessus. Son rôle de découverte l'indique alors. Le manager classe le compte en découverte seule au lieu de le considérer comme un compte sans rôle de commande.

Avec l'AWS CLI

Chaque version publie également un script équivalent. Définissez ACCOUNT, MANAGER_ACCOUNT, ENVS (les environnements du manager, séparés par des espaces) et ORGANIZATION en tête du script ou dans l'environnement. Exécutez-le ensuite avec des identifiants d'administrateur du compte. Le script commence par les vérifier, puis crée les rôles, ou les met à jour s'il est exécuté de nouveau. Les noms de rôles peuvent inclure un chemin (DISCOVERY_ROLE, COMMAND_ROLE). Un COMMAND_ROLE vide configure un compte découvert mais jamais mis en veille.

curl -O https://releases.dormeto.com/manager/0.21.0/dormeto-access-commands-0.21.0.sh
curl -O https://releases.dormeto.com/manager/0.21.0/SHA256SUMS
shasum -a 256 -c --ignore-missing SHA256SUMS
ACCOUNT=222233334444 MANAGER_ACCOUNT=111122223333 ENVS=prod ORGANIZATION=o-exampleorgid bash dormeto-access-commands-0.21.0.sh

La politique de délégation se règle dans le compte de gestion. Remplacez le compte et l'environnement du manager dans son principal (arn:aws:iam::MANAGER_ACCOUNT:role/dmt-ENV-manager-discovery, un par environnement). Fusionnez-la ensuite avec la politique existante de l'organisation, le cas échéant. L'organisation n'a qu'une seule politique : en écrire une remplace toutes ses autres déclarations. Avec jq :

curl -O https://releases.dormeto.com/manager/0.21.0/dormeto-organization-policy.json
aws organizations describe-resource-policy --query ResourcePolicy.Content --output text > current.json \
  || echo '{"Statement":[]}' > current.json
jq -s '{Version: "2012-10-17", Statement: ([.[0].Statement[] | select(.Sid != "DormetoReadOrganization")] + .[1].Statement)}' \
  current.json dormeto-organization-policy.json > merged.json
aws organizations put-resource-policy --content file://merged.json

Comment le manager installe les routeurs

Le manager ne détient aucun identifiant pour vos comptes. Pour installer, mettre à jour ou supprimer un routeur, il assume un rôle dans le compte du routeur : le rôle de commande (DmtCommandRole par défaut). Il agit à travers lui par appels d'API AWS. Chaque appel figure dans le CloudTrail de ce compte, émis par assumed-role/DmtCommandRole/dmt-<env>-operations.

De votre demande au routeur

  1. Vous demandez, dans le tableau de bord ou avec la CLI : installer, mettre à jour ou désinstaller un routeur. Ou intégrer un workload dans un compte et une région sans routeur : l'intégration l'installe d'abord. Avec le rafraîchissement sur événement, une exécution de la découverte connecte aussi un nouveau compte de la même façon. Cela passe par un rôle de relais, et une règle par région.
  2. L'API du manager enregistre l'opération et démarre le workflow Step Functions dmt-<env>-manager-operations, dans le compte du manager.
  3. Chaque étape s'exécute dans la fonction Lambda dmt-<env>-manager-operations, sous le rôle du même nom. Ce rôle ne peut assumer qu'un seul nom de rôle, celui du rôle de commande. Il ne le peut que dans les comptes de votre organisation (aws:ResourceOrgID).
  4. Le rôle de commande : l'étape appelle sts:AssumeRole sur arn:aws:iam::<account>:role/DmtCommandRole, session dmt-<env>-operations, pour une heure. La politique de confiance du rôle n'accepte que ce rôle du compte du manager, désigné par son nom.
  5. Les ressources du routeur : avec cette session, l'étape crée le routeur à partir de son blueprint, dans son propre espace de noms. D'abord les rôles dmtr-<env>-<region>-controller, -waker, -scheduler et -onboarder sous /dormeto/router/. Chacun est soumis à la limite d'autorisations DmtRouterBoundary. Puis les fonctions, la table, les files, les groupes de logs et la planification dmtr-<env>-*. Puis les access entries des routeurs dans les clusters EKS de la région. Pour les clusters privés, leurs fonctions proxy dans les VPC des clusters.
  6. Le routeur s'exécute ensuite sous ses propres rôles, dans votre compte. L'état, les réveils, les mises en veille et les pauses n'utilisent pas le rôle de commande. Le rôle de l'API du manager (dmt-<env>-manager-api) appelle les fonctions du routeur, dont les politiques de ressource l'autorisent.

À chaque exécution de la découverte, la vérification d'accès assume le rôle de commande dans chaque compte pour 15 minutes. Elle indique seulement si elle a pu le faire. C'est dmt-<env>-manager-access-check, sous le rôle des opérations. La découverte liste les comptes où elle n'a pas pu, et l'intégration y est refusée, avec la raison.

Le rôle par défaut

DmtCommandRole, sous le chemin racine, dans chaque compte où des workloads sont mis en veille : un seul nom pour toute l'organisation. Le module d'accès et le script AWS CLI le créent, avec sa politique et la politique DmtRouterBoundary (ci-dessus). Le compte du manager les reçoit du module du manager.

Un autre nom ou chemin

Nommez-le selon vos règles, chemin compris, de la même façon dans chaque compte. Donnez ce nom au manager et à ce qui crée le rôle :

module "dormeto" {
  source            = "https://releases.dormeto.com/manager/0.21.0/terraform-aws-dormeto-0.21.0.zip//modules/manager"
  # … your other inputs
  command_role_name = "platform/DormetoRouters"
}

module "dormeto_access_shop" {
  source            = "https://releases.dormeto.com/manager/0.21.0/dormeto-access-0.21.0.zip"
  # … as above
  command_role_name = "platform/DormetoRouters"
}

Avec le script AWS CLI, COMMAND_ROLE=platform/DormetoRouters. Le rôle d'opérations du manager ne peut alors assumer que arn:aws:iam::*:role/platform/DormetoRouters. Créez d'abord le rôle dans chaque compte, puis appliquez le manager avec son nom. Jusque-là, la découverte liste les comptes où il ne peut pas l'assumer.

Votre propre rôle

Vous pouvez créer le rôle de commande avec vos propres outils. Le manager vérifie seulement qu'il peut l'assumer. Chaque étape a ensuite besoin de ceci :

ÉlémentCe qu'il lui faut
NomLe même nom et le même chemin dans chaque compte, donnés au manager (command_role_name). Une durée de session maximale d'une heure ou plus (la valeur par défaut).
ConfianceLe rôle d'opérations du manager, désigné par son nom dans son compte, un par environnement (ci-dessous). Désigné par son nom, le rôle peut exister avant le manager et reste valide après sa réinstallation.
AutorisationsLa politique de la version, command-role/command-policy.json dans dormeto-access-0.21.0.zip, avec ${account} et ${partition} remplacés. Elle n'atteint que l'espace de noms des routeurs et, pour les clusters privés, des ressources délimitées par des tags. Ce sont les groupes de sécurité portant dormeto:role = kubernetes-proxy et les groupes de sécurité des clusters EKS (tag aws:eks:cluster-name). Les ressources dmtr-* et les rôles sous /dormeto/router/ restent comme avant.
LimiteLa politique gérée DmtRouterBoundary, sous ce nom et au chemin racine. Elle vient de router-boundary.json dans la même archive, remplie de la même façon. Le rôle de commande ne peut créer un rôle que s'il porte cette limite. Le manager la donne à chaque rôle qu'il crée. Un rôle de routeur ne peut jamais faire plus que ce que la limite autorise.
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Action": "sts:AssumeRole",
    "Principal": { "AWS": "arn:aws:iam::111122223333:root" },
    "Condition": {
      "ArnLike": { "aws:PrincipalArn": ["arn:aws:iam::111122223333:role/dmt-prod-manager-operations"] }
    }
  }]
}
  • Vous pouvez ajouter des tags, une description et une condition sur aws:PrincipalOrgID. Vous pouvez aussi mettre une limite d'autorisations à vous sur le rôle de commande lui-même, si vos règles en exigent une sur chaque rôle. Elle doit autoriser chaque action de la politique.
  • Gardez le nom de la limite, l'espace de noms et chaque déclaration de la politique. Une étape à qui il manque une autorisation échoue, avec l'erreur d'AWS, dans la vue Operations.
  • Une politique de contrôle des services (SCP) qui exige sa propre limite sur chaque nouveau rôle doit accepter DmtRouterBoundary sur les rôles sous /dormeto/router/. Un rôle ne porte qu'une limite.

Les deux exemples ci-dessous créent le rôle de commande, la limite et le rôle de découverte, comme le fait le module d'accès. Le rôle de découverte garde son nom, DmtDiscoveryRole : la politique du rôle de commande le désigne pour les access entries des clusters.

Votre propre rôle avec Terraform

Les politiques de la version, inchangées, dans un module à vous. Téléchargez l'archive, vérifiez-la et décompressez-la à côté de votre code :

curl -O https://releases.dormeto.com/manager/0.21.0/dormeto-access-0.21.0.zip
curl -O https://releases.dormeto.com/manager/0.21.0/SHA256SUMS
shasum -a 256 -c --ignore-missing SHA256SUMS
unzip dormeto-access-0.21.0.zip -d dormeto-access

dormeto-roles/main.tf :

terraform {
  required_providers {
    aws = { source = "hashicorp/aws" }
  }
}

variable "manager_account_id" { type = string }
variable "envs" { type = list(string) }
variable "organization_id" { type = string }

data "aws_caller_identity" "current" {}
data "aws_partition" "current" {}

locals {
  files   = "${path.module}/../dormeto-access" # dormeto-access-0.21.0.zip, unzipped
  vars    = { account = data.aws_caller_identity.current.account_id, partition = data.aws_partition.current.partition }
  manager = "arn:${local.vars.partition}:iam::${var.manager_account_id}"
  # Each role trusts one role of the manager, by name in its account, one per environment.
  trust = { for role in ["operations", "discovery"] : role => jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Effect    = "Allow"
      Action    = "sts:AssumeRole"
      Principal = { AWS = "${local.manager}:root" }
      Condition = {
        ArnLike      = { "aws:PrincipalArn" = [for env in var.envs : "${local.manager}:role/dmt-${env}-manager-${role}"] }
        StringEquals = { "aws:PrincipalOrgID" = var.organization_id }
      }
    }]
  }) }
}

# Your name and path: give the same to the manager (command_role_name).
resource "aws_iam_role" "command" {
  name                 = "DormetoRouters"
  path                 = "/platform/"
  max_session_duration = 3600
  assume_role_policy   = local.trust["operations"]
  # permissions_boundary = "arn:aws:iam::222233334444:policy/YourBoundary"
}

resource "aws_iam_role_policy" "command" {
  name   = "command"
  role   = aws_iam_role.command.id
  policy = templatefile("${local.files}/command-role/command-policy.json", local.vars)
}

# This name, at the root: the manager gives it to every role it creates for a router.
resource "aws_iam_policy" "boundary" {
  name        = "DmtRouterBoundary"
  description = "Permissions boundary of every role Dormeto creates for a router."
  policy      = templatefile("${local.files}/router-boundary.json", local.vars)
}

resource "aws_iam_role" "discovery" {
  name                 = "DmtDiscoveryRole"
  max_session_duration = 3600
  assume_role_policy   = local.trust["discovery"]
  tags                 = { "dormeto:component" = "discovery" } # it reads its own role's tags by this one
}

resource "aws_iam_role_policy" "discovery" {
  name   = "discovery"
  role   = aws_iam_role.discovery.id
  policy = file("${local.files}/discovery-policy.json")
}

Une instance par compte, avec un provider par compte comme ci-dessus, puis command_role_name = "platform/DormetoRouters" dans le module du manager :

module "dormeto_roles_shop" {
  source             = "./dormeto-roles"
  providers          = { aws = aws.shop }
  manager_account_id = "111122223333"
  envs               = ["prod"]
  organization_id    = "o-exampleorgid"
}

À chaque nouvelle version, décompressez son archive à la place de la précédente et lancez un plan. Son entrée dans Versions indique si les rôles changent.

Votre propre rôle avec un StackSet CloudFormation

Si votre organisation déploie déjà ses rôles avec des StackSets, les mêmes rôles tiennent dans une seule stack. Elle atteint chaque nouveau compte d'une unité d'organisation. Dormeto ne crée jamais de stack lui-même. Vous construisez le modèle à partir des politiques de la version : il suit donc chaque version. Avec jq, là où vous avez décompressé l'archive :

MANAGER_ACCOUNT=111122223333 ENVS="prod" ORGANIZATION=o-exampleorgid COMMAND_ROLE=platform/DormetoRouters
jq -n --arg manager "$MANAGER_ACCOUNT" --arg envs "$ENVS" --arg org "$ORGANIZATION" --arg command "$COMMAND_ROLE" \
  --slurpfile commandPolicy dormeto-access/command-role/command-policy.json \
  --slurpfile boundary dormeto-access/router-boundary.json \
  --slurpfile discovery dormeto-access/discovery-policy.json '
  def name($full): ($full | split("/")) as $p
    | {RoleName: $p[-1], Path: (if ($p | length) > 1 then "/\($p[:-1] | join("/"))/" else "/" end)};
  def trust($role): {Version: "2012-10-17", Statement: [{Effect: "Allow", Action: "sts:AssumeRole",
    Principal: {AWS: "arn:${partition}:iam::\($manager):root"},
    Condition: {ArnLike: {"aws:PrincipalArn": [$envs | splits(" +") | select(. != "")
        | "arn:${partition}:iam::\($manager):role/dmt-\(.)-manager-\($role)"]},
      StringEquals: {"aws:PrincipalOrgID": $org}}}]};
  {AWSTemplateFormatVersion: "2010-09-09", Description: "Dormeto organization roles", Resources: {
    CommandRole: {Type: "AWS::IAM::Role", Properties: (name($command) + {MaxSessionDuration: 3600,
      AssumeRolePolicyDocument: trust("operations"), Policies: [{PolicyName: "command", PolicyDocument: $commandPolicy[0]}]})},
    RouterBoundary: {Type: "AWS::IAM::ManagedPolicy", Properties: {ManagedPolicyName: "DmtRouterBoundary",
      Description: "Permissions boundary of every role Dormeto creates for a router.", PolicyDocument: $boundary[0]}},
    DiscoveryRole: {Type: "AWS::IAM::Role", Properties: {RoleName: "DmtDiscoveryRole", MaxSessionDuration: 3600,
      AssumeRolePolicyDocument: trust("discovery"), Policies: [{PolicyName: "discovery", PolicyDocument: $discovery[0]}],
      Tags: [{Key: "dormeto:component", Value: "discovery"}]}}}}
  | walk(if type == "string" and test("\\$\\{(account|partition)\\}")
      then {"Fn::Sub": (gsub("\\$\\{account\\}"; "${AWS::AccountId}") | gsub("\\$\\{partition\\}"; "${AWS::Partition}"))}
      else . end)' > dormeto-roles.json

Puis, depuis le compte de gestion ou un administrateur délégué pour les StackSets (ajoutez --call-as DELEGATED_ADMIN), avec l'accès approuvé des StackSets activé (aws cloudformation activate-organizations-access) :

aws cloudformation create-stack-set --stack-set-name dormeto-roles \
  --template-body file://dormeto-roles.json --capabilities CAPABILITY_NAMED_IAM \
  --permission-model SERVICE_MANAGED --auto-deployment Enabled=true,RetainStacksOnAccountRemoval=false
aws cloudformation create-stack-instances --stack-set-name dormeto-roles --regions us-east-1 \
  --deployment-targets OrganizationalUnitIds=ou-exmp-12345678,Accounts=111122223333,AccountFilterType=DIFFERENCE
  • Une seule région : IAM est global. Une deuxième région créerait les mêmes rôles une seconde fois, et échouerait.
  • Sans le compte du manager (AccountFilterType=DIFFERENCE) : le module du manager crée ses rôles. Un StackSet n'atteint jamais non plus le compte de gestion, qui n'a besoin que de la politique de délégation.
  • Un nouveau compte de l'unité d'organisation reçoit les rôles, et la prochaine exécution de la découverte le trouve.
  • Une nouvelle version : reconstruisez le modèle à partir de son archive, puis aws cloudformation update-stack-set --stack-set-name dormeto-roles --template-body file://dormeto-roles.json --capabilities CAPABILITY_NAMED_IAM.
  • Suppression : désinstallez d'abord les routeurs, puis delete-stack-instances avec les mêmes cibles et --no-retain-stacks, et delete-stack-set.

Kubernetes (EKS)

Dormeto met en veille les Deployments et StatefulSets d'un cluster EKS situés derrière un ALB de l'AWS Load Balancer Controller. Les routeurs appellent l'API du cluster avec leurs propres rôles, au moyen des access entries EKS. Rien ne s'exécute dans le cluster. Le point de terminaison de l'API du cluster doit être public et ouvert à toutes les adresses (0.0.0.0/0), ou son accès privé doit être activé. Les routeurs le joignent alors par une petite fonction proxy dans son VPC (Clusters privés).

  • Access entries : les rôles des routeurs (dmtr-<env>-<region>-controller, -waker, -onboarder, sous /dormeto/router/) dans le groupe Kubernetes dormeto:router. Aussi DmtDiscoveryRole avec la politique en lecture seule AmazonEKSViewPolicy (sans accès aux Secrets). Le manager crée ces entrées au moyen de DmtCommandRole lorsqu'il installe ou met à jour un routeur. Il le fait dans chaque cluster du compte et de la région du routeur dont le mode d'authentification est API ou API_AND_CONFIG_MAP. La suppression du routeur supprime les entrées de ses rôles.
  • Les droits de dormeto:router, publiés avec chaque version. Un ClusterRole accorde exactement ce que vérifient les routeurs : lecture des Deployments, StatefulSets, ReplicaSets, Pods, Services, Events, Ingresses, HorizontalPodAutoscalers et ScaledObjects KEDA. Lecture des Nodes. Mise à l'échelle des Deployments et StatefulSets. Annotation des ScaledObjects. Création, modification et suppression d'Ingresses. Son binding l'accompagne, avec une politique d'admission. Celle-ci interdit au groupe de créer ou de supprimer un Ingress sans le label dormeto.com/managed. Elle lui interdit aussi toute modification qui ajoute ou retire ce label. Elle demande Kubernetes 1.30 ou plus récent. Sur les versions antérieures, le groupe peut créer et supprimer n'importe quel Ingress. Appliquez ce manifeste une fois par cluster, avec un accès administrateur :
curl -O https://releases.dormeto.com/manager/0.21.0/dormeto-kubernetes-0.21.0.yaml
curl -O https://releases.dormeto.com/manager/0.21.0/SHA256SUMS
shasum -a 256 -c --ignore-missing SHA256SUMS
kubectl apply -f dormeto-kubernetes-0.21.0.yaml

Si vous préférez déclarer les access entries dans votre propre Terraform (compte 222233334444, environnement prod, région us-east-1) :

resource "aws_eks_access_entry" "dormeto_router" {
  for_each          = toset(["controller", "waker", "onboarder"])
  cluster_name      = "my-cluster"
  principal_arn     = "arn:aws:iam::222233334444:role/dormeto/router/dmtr-prod-us-east-1-${each.key}"
  kubernetes_groups = ["dormeto:router"]
}

resource "aws_eks_access_entry" "dormeto_discovery" {
  cluster_name  = "my-cluster"
  principal_arn = "arn:aws:iam::222233334444:role/DmtDiscoveryRole"
}

resource "aws_eks_access_policy_association" "dormeto_discovery" {
  cluster_name  = "my-cluster"
  principal_arn = aws_eks_access_entry.dormeto_discovery.principal_arn
  policy_arn    = "arn:aws:eks::aws:cluster-access-policy/AmazonEKSViewPolicy"
  access_scope {
    type = "cluster"
  }
}

Un cluster qui utilise uniquement la ConfigMap aws-auth (mode d'authentification CONFIG_MAP) n'a pas d'access entries. Passez-le en API_AND_CONFIG_MAP (la décision vous appartient : ce changement est irréversible, et aws-auth continue de fonctionner). Mettez ensuite à jour le routeur ou intégrez un workload pour que le manager crée les entrées. Vous pouvez aussi mapper vous-même les rôles dans aws-auth, qui identifie un rôle par son ARN, sans le chemin. Placez les rôles des routeurs dans dormeto:router. Placez DmtDiscoveryRole dans un groupe lié au ClusterRole en lecture seule view (kubectl create clusterrolebinding dormeto-discovery --clusterrole=view --group=dormeto:discovery) :

mapRoles: |
  - rolearn: arn:aws:iam::222233334444:role/dmtr-prod-us-east-1-controller
    username: dormeto-controller
    groups: [dormeto:router]
  - rolearn: arn:aws:iam::222233334444:role/dmtr-prod-us-east-1-waker
    username: dormeto-waker
    groups: [dormeto:router]
  - rolearn: arn:aws:iam::222233334444:role/dmtr-prod-us-east-1-onboarder
    username: dormeto-onboarder
    groups: [dormeto:router]
  - rolearn: arn:aws:iam::222233334444:role/DmtDiscoveryRole
    username: dormeto-discovery
    groups: [dormeto:discovery]

Vérification : à son installation, à chaque mise à jour et avant chaque intégration, le routeur demande au cluster ce qu'il a le droit de faire. Sa vue dans Routers liste les clusters de son compte et de sa région, indique s'il peut les joindre et quels droits lui manquent. La boîte de dialogue d'intégration d'un workload Kubernetes affiche les mêmes informations. L'intégration reste bloquée tant qu'un droit manque. Appliquez alors le manifeste, puis relancez l'intégration.

La vérification indique aussi comment chaque cluster est joint : directement, ou par son proxy (son nom et sa version).

Clusters privés

Un cluster dont l'accès privé est activé est joint par une fonction proxy dans son VPC. Son point de terminaison public est alors désactivé, ou limité à certaines adresses. Un cluster dont le point de terminaison est public pour toutes les adresses est appelé directement, comme avant. C'est vrai même si son accès privé est aussi activé. Un cluster peut avoir son accès privé désactivé et son point de terminaison public limité à certaines adresses. Il ne peut alors pas être intégré. La découverte le signale : activez l'accès privé.

  • Le proxy : une petite fonction Lambda par cluster, <router>-kube-<cluster>, rattachée aux sous-réseaux du cluster. Elle a son propre groupe de sécurité : TCP 443 en sortie dans le VPC. Une règle sur le groupe de sécurité du cluster admet le TCP 443 venant d'elle. Le routeur et la découverte l'invoquent avec l'API Lambda et envoient leurs propres jetons EKS. Le proxy n'a aucune identité Kubernetes ni aucune permission AWS en dehors de ses interfaces réseau. Il ne parle qu'au point de terminaison de son cluster. Les access entries ci-dessus restent nécessaires, puisque le proxy transmet l'identité de l'appelant.
  • Ce que cela coûte : des invocations Lambda seulement, quelques centimes par mois. Pas de NAT gateway, pas de point de terminaison VPC, et rien ne s'exécute dans le cluster.
  • Qui le crée : le manager crée, met à jour et supprime les proxies des routeurs qu'il installe. Il le fait à l'installation, à la mise à jour, à l'intégration et à l'accès au cluster. La désinstallation du routeur les supprime. Il leur faut le routeur 0.33.0.
  • Avec Terraform, un routeur que vous avez écrit obtient ses proxies du module kubernetes-proxy du dépôt du routeur. Il y en a un par cluster, à côté de eks-access. Ses entrées sont router_name et lambda_source_dir (comme pour le module du routeur), cluster_name et router_version, et en option subnet_ids et security_group_ids. Avec security_group_ids fourni, le module n'ajoute aucune règle. Vous fournissez des groupes qui joignent le VPC en TCP 443, admis par le groupe de sécurité du cluster en TCP 443. subnet_ids n'y change rien. Détruisez-le avant le VPC du cluster.
  • Les nouvelles permissions, à appliquer de nouveau dans chaque compte membre avant de mettre à jour ses routeurs. DmtRouterBoundary gagne ec2:CreateNetworkInterface, ec2:DescribeNetworkInterfaces, ec2:DescribeSubnets, ec2:DeleteNetworkInterface, ec2:AssignPrivateIpAddresses et ec2:UnassignPrivateIpAddresses (pour le rôle du proxy). DmtCommandRole gagne ec2:DescribeSecurityGroups, ec2:DescribeSubnets, ec2:DescribeVpcs et ec2:DescribeNetworkInterfaces. Il gagne ec2:CreateSecurityGroup et ec2:CreateTags, avec le tag dormeto:role = kubernetes-proxy à la création. C'est dans le VPC du cluster, quel que soit le compte qui le possède. Un VPC partagé par RAM convient. Il gagne lambda:ListTags sur ses fonctions dmtr-*, pour rétablir les tags d'un proxy. Il gagne les règles de sortie et la suppression sur les groupes portant ce tag. Il gagne les règles d'entrée sur les groupes de sécurité des clusters EKS (tag aws:eks:cluster-name). DmtDiscoveryRole peut invoquer (lambda:InvokeFunction) les fonctions nommées *-kube-* portant le tag dormeto:role = kubernetes-proxy.

Suppression

Commencez par désinstaller les routeurs depuis le manager. Cela supprime leurs access entries dans les clusters EKS. Cela supprime aussi les fonctions proxy des clusters privés, avec leur règle TCP 443 sur le groupe de sécurité du cluster. Dans chaque cluster EKS, exécutez kubectl delete -f dormeto-kubernetes-0.21.0.yaml et aws eks delete-access-entry --cluster-name my-cluster --principal-arn arn:aws:iam::222233334444:role/DmtDiscoveryRole. Ou exécutez terraform destroy sur vos access entries, et sur vos modules kubernetes-proxy avant les VPC des clusters. Dans chaque compte membre, exécutez terraform destroy sur le module d'accès. Si vous avez utilisé l'AWS CLI, supprimez les politiques en ligne discovery et command, les rôles et la politique DmtRouterBoundary. Dans le compte de gestion, retirez uniquement la déclaration de Dormeto. Avec le module, exécutez terraform destroy si la politique ne contient rien d'autre. Avec additional_statements, retirez plutôt le module de votre état Terraform avec terraform state rm, puis lancez les commandes ci-dessous. Avec l'AWS CLI :

aws organizations describe-resource-policy --query ResourcePolicy.Content --output text \
  | jq '.Statement |= map(select(.Sid != "DormetoReadOrganization"))' > rest.json
jq -e '.Statement | length > 0' rest.json > /dev/null \
  && aws organizations put-resource-policy --content file://rest.json \
  || aws organizations delete-resource-policy

Vérification

Dans le manager, la découverte affiche le panneau Organization access : les comptes prêts, ceux auxquels il manque un rôle, et la raison. Run now relance la vérification. Si le rôle de commande est absent, le tableau de bord le signale avant toute intégration. Si la politique de délégation est absente, la page Perimeter indique que le mode organisation est indisponible.