Aws-external-dns: различия между версиями

Материал из noname.com.ua
Перейти к навигацииПерейти к поиску
Строка 31: Строка 31:
 
** Конкретный экзкмпляр Kubernetes пода (через запуск пода от имени Service Account) через OIDC
 
** Конкретный экзкмпляр Kubernetes пода (через запуск пода от имени Service Account) через OIDC
   
* Роль привязывается к <code>trust policy</code>
+
* Роль привязывается к <code>trust policy</code> (trust policy можно считать особым типом IAM Role? ну или что-то около того)
 
* Создается сераисный аккаунт с аннотацией
 
* Создается сераисный аккаунт с аннотацией
 
<PRE>
 
<PRE>

Версия 12:58, 23 июня 2025


Постановка задачи

Задача: есть некоторый базовый домен mydomain.tld, который лежит на серверах AWS в Route53
Требуется при разворачивании приложения в EKS автоматически создавать записи типа CNAME и
направлять их на балансировщик (Ingress или другой, в перспективе ALB но пока Ingress), при запуске экземпляра приложения, например для
экземпляра staging создать записи

  • backend.staging.mydomain.tld
  • frontend.staging.mydomain.tld
  • что-то-еще.staging.mydomain.tld

Имя экземпляра приложения staging может быть произвольным

Обзор решения

Для того что бы работать с доменами как с ресурсами k8s требуется обработчик этих ресурсов,
в этом случае это ExternalDns
Далее настройки касаются только AWS, в случае других провайдеров/регистраторо настройки будут отличаться

  • Создать роль которая разрешает модификацию DNS
  • Создать политику Trust Policy — это специальный документ JSON, который определяет, кто имеет право "представлять" IAM роль, то есть использовать её права.

Она не определяет, что роль может делать. Она определяет, кто может её использовать. Например:

    • EC2-инстанс
    • Lambda-функция
    • Конкретный экзкмпляр Kubernetes пода (через запуск пода от имени Service Account) через OIDC
  • Роль привязывается к trust policy (trust policy можно считать особым типом IAM Role? ну или что-то около того)
  • Создается сераисный аккаунт с аннотацией
apiVersion: v1
kind: ServiceAccount
metadata:
  name: my-sa
  namespace: my-namespace
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::<ACCOUNT_ID>:role/MyEksIamRole

Который будет обладать всеми правами прописанными в полиси

  • Под этим аккаунтом запускается POD который следит за ДНС и вносит изменения при необходимости

IAM Policy

Для начала потребуется создать политику следующего вида:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "ExternalDNSAccess",
      "Effect": "Allow",
      "Action": [
        "route53:ChangeResourceRecordSets",
        "route53:ListResourceRecordSets"
      ],
      "Resource": [
        "arn:aws:route53:::hostedzone/Z1038XXXXXXXXXXXXXXX",
        "arn:aws:route53:::hostedzone/Z0235XXXXXXXXXXXXXXX"
    ]
    },
    {
      "Effect": "Allow",
      "Action": "route53:ListHostedZones",
      "Resource": "*"
    }
  ]
}

В том пример присутствуют две записи:

"arn:aws:route53:::hostedzone/Z1038XXXXXXXXXXXXXXX",
"arn:aws:route53:::hostedzone/Z0235XXXXXXXXXXXXXXX"

так как приложение использует более чем одну зону.


Для получения Id (Z1038XXXXXXXXXXXXXXX в примере) для домена mydomain.tld использовать комманду

aws route53 list-hosted-zones-by-name | jq '.HostedZones[] | select(.Name=="mydomain.tld") | .Id'

Создание IAM Role

Далее требуется создать роль (которая далее будет привязана к Service Account).
Пример роли (в web console я не нашл как вставить сразу json но результат можно посмотреть в таком виде и сравнить с желаемым):

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "sts:AssumeRoleWithWebIdentity",
            "Principal": {
                "Federated": "arn:aws:iam::54XXXXXXXXXX:oidc-provider/oidc.eks.us-east-1.amazonaws.com/id/5918A6B3305CXXXXXXXXXXXXXXXXXXXX"
            },
            "Condition": {
                "StringEquals": {
                    "oidc.eks.us-east-1.amazonaws.com/id/5918A6B3305CXXXXXXXXXXXXXXXXXXXX:sub": [
                        "system:serviceaccount:external-dns:external-dns"
                    ],
                    "oidc.eks.us-east-1.amazonaws.com/id/5918A6B3305CXXXXXXXXXXXXXXXXXXXX:aud": [
                        "sts.amazonaws.com"
                    ]
                }
            }
        }
    ]
}

Значения

  • arn:aws:iam::54XXXXXXXXXX это ID аккаунта
  • oidc.eks.us-east-1.amazonaws.com/id/5918A6B3305CXXXXXXXXXXXXXXXXXXXX как правильно называется это значение,

я не знаю, но получить его можно следующей коммандой:

aws eks describe-cluster --name education-eks-1o3RFCvh --query "cluster.identity.oidc.issuer"

  • education-eks-1o3RFCvh это имя кластера

Вывод команды будет примерно таким:

"https://oidc.eks.us-east-1.amazonaws.com/id/5918A6B3305CXXXXXXXXXXXXXXXXXXXX"

Icon-caution.gif

В интиерентаах пишут что нужно отдельно включать OIDC командой

eksctl utils associate-iam-oidc-provider --region=us-east-2 --cluster=education-eks-1o3RFCvh --approve

но возможно эта информация уже устарела или зависит от того как именно создавался кластер

Привязка политики к роли

Я "накликал" это в Web Console :(

External DNS

ExternalDNS это код который работает внутри кластера k8s от имени сервисного аккаунта,
связанного с IAM ролью и за счет этого получает все права, которые есть у роли

Подготовительная работа


Добавить репозиторий

helm repo add bitnami https://charts.bitnami.com/bitnami

При желании для изучения можно скачать чарт:

helm pull bitnami/external-dns

Создать отдельный namespace (опционально - но лучше конечно создавать):

kubectl create namespace external-dns

Подготовить конфигурационный файл SERVICE-ACCOUNT-external-dns.yaml для сервисного аккаунта следующего содержания:

---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: external-dns
  namespace: external-dns
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::54XXXXXXXXXX:role/ExternalDNSServiceAccountRole

В этом файле ключевой является аннотация:

  • arn:aws:iam::54XXXXXXXXXX:role/ExternalDNSServiceAccountRole - это ссылка на созданную IAM ROLE с правами работы с DNS

Создать Service Account

kubectl apply -f SERVICE-ACCOUNT-external-dns.yaml
serviceaccount/external-dns created


Icon-caution.gif

ExternalDNS будет обрабатывать только те ресурсы, у которых аннотация
external-dns.alpha.kubernetes.io/controller
совпадает с указанной в параметре --controller.
Остальные Ingress, даже с нужными доменами, игнорируются.

Установка

Устанавлить External DNS с нужными параметрами

helm upgrade \
    --install external-dns bitnami/external-dns \
    --namespace external-dns \
    --set serviceAccount.name=external-dns \
    --set serviceAccount.create=false \
    --set provider=aws \
    --set sources={ingress} \
    --set domainFilters[0]=mydomain.tld \
    --set domainFilters[1]=myseconddomain.tld \
    --set policy=upsert-only \
    --set registry=txt \
    --set txtOwnerId=external-dns \
    --set logLevel=debug
  • serviceAccount.name=external-dns - использовать предсозданный Service Account
  • serviceAccount.create=false - не создавать Service Account при установке chart
  • provider=aws - очевидно
  • sources={ingress} - смотреть на домены только на Ingress (это массив, его элементы можно перечислить, я не уверен что это елинственно-возможный синтаксис)
  • domainFilters[0]=mydomain.tld - оционально, разрешить работу только с 2 зонами (это тоже массив)
  • domainFilters[1]=myseconddomain.tld
  • policy=upsert-only насколько я понимаю, эта опция означает "не удалять", другими словами при удалении Ingress запись останется (вероятно это более безопасный вариант?)
  • registry=txt
  • txtOwnerId=external-dns
  • logLevel=debug (options: panic, debug, info, warning, error, fatal, trace)

Icon-caution.gif

Нигде в документации толком не сказано, что за опция txt-owner-id — она определяет значения TXT-записи,
которая создаётся ExternalDNS для записей, которые он создаёт, что бы отменить их как «свои», т.е. те, которые управляются им.
Если, к примеру, у вас в домене уже есть запись subdomain.example.com, и к ней нет TXT,
которую добавляет ExternalDNS, то при создании Ingress с host: subdomain.example.comExternalDNS
ничего с существующей записью не сделает.
(https://rtfm.co.ua/ru/kubernetes-obnovlenie-dns-v-route53-pri-sozdanii-ingress/)

Настройка Ingress

Настройка Ingress сводится к казанию правильной аннотации

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    ...
    external-dns.alpha.kubernetes.io/controller: dns-controller
    ...

Дополнительно проверить

  • Для домашней лабы - интеграцию с Mikrotk (Вроде бы заявлено)