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

Материал из noname.com.ua
Перейти к навигацииПерейти к поиску
Строка 176: Строка 176:
 
* <code> serviceAccount.create=false</code> - не создавать Service Account при установке chart
 
* <code> serviceAccount.create=false</code> - не создавать Service Account при установке chart
 
* <code> provider=aws</code> - очевидно
 
* <code> provider=aws</code> - очевидно
  +
* <code> sources={ingress}</code> - смотреть на домены только на ingress (это массив, его элементы можно перечислить, я не уверен что это елинственно-возможный синтаксис)
* <code> sources={ingress}</code>
 
* <code> domainFilters[0]=mydomain.tld</code>
+
* <code> domainFilters[0]=mydomain.tld</code> - оционально, разрешить работу только с 2 зонами (это тоже массив)
 
* <code> domainFilters[1]=myseconddomain.tld</code>
 
* <code> domainFilters[1]=myseconddomain.tld</code>
 
* <code> policy=upsert-only</code>
 
* <code> policy=upsert-only</code>
 
* <code> registry=txt</code>
 
* <code> registry=txt</code>
 
* <code> txtOwnerId=external-dns</code>
 
* <code> txtOwnerId=external-dns</code>
* <code> logLevel=debug</code>
+
* <code> logLevel=debug</code> (options: panic, debug, info, warning, error, fatal, trace)
  +
  +
{{caution|text=
  +
Нигде в документации толком не сказано, что за опция «txt-owner-id» — она определяет значения TXT-записи, которая создаётся ExternalDNS для записей, которые он создаёт, что бы отменить их как «свои», т.е. те, которые управляются им.
  +
  +
Если, к примеру, у вас в домене уже есть запись subdomain.example.com, и к ней нет TXT, которую добавляет ExternalDNS, то при создании Ingress с host: subdomain.example.com — ExternalDNS ничего с существующей записью не сделает.
  +
(https://rtfm.co.ua/ru/kubernetes-obnovlenie-dns-v-route53-pri-sozdanii-ingress/)
  +
}}

Версия 14:33, 8 июня 2025

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

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

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

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

Решение

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

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

External DNS

External DNS это код который работает внутри кластера 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




external-dns будет обрабатывать только те ресурсы, у которых аннотация 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
  • 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.com — ExternalDNS ничего с существующей записью не сделает. (https://rtfm.co.ua/ru/kubernetes-obnovlenie-dns-v-route53-pri-sozdanii-ingress/)