Оптимізація DevOps-процесів за допомогою єдиного входу (SSO): переваги, проблеми та практичні приклади

Усі статті, обговорення, новини про DevOps — в одному місці. Підписуйтеся на DOU | DevOps!

У кращих практихах DevOps безпроблемна інтеграція єдиного входу (Single Sign-On, SSO) стає ключовим фактором підвищення ефективності, безпеки та зручності користувачів. Оскільки організації прагнуть пришвидшити розробку і доставку програмного забезпечення, важливість уніфікованого та безпечного механізму автентифікації неможливо переоцінити.

Єдиний вхід не тільки спрощує керування доступом, дозволяючи користувачам входити один раз і отримувати доступ до кількох систем, але й також відіграє вирішальну роль у посиленні загальних заходів кібербезпеки.

У цій статті розглядається перетин DevOps і SSO, а також описуються переваги, проблеми та практики, які виникають під час інтеграції єдиного входу в структуру робочого процесу проєкту.

Насамперед визначивши необхідність упровадження єдиного входу для всіх застосунків і на всіх рівнях, де це можливо, потрібно ретельно оглянути програми та сервіси, які використовуються в проєкті. Розгляньмо рішення, які використовує моя команда, розподіливши їх за рівнями складності внесення змін і рівнем ієрархії у проєкті.

Розпочнемо із застосунків: Grafana для моніторингу, Jenkins для безперервної інтеграції (CI) й Argo CD для безперервної доставки (CD). Далі йде Amazon EKS, оскільки всі зазначені інструменти розгортаються саме в ньому, а налаштування доступу до нього виявляється більш складним завданням.

Завершимо ми не менш важливим налаштуванням платформи Amazon Web Services (AWS), де нам доведеться забезпечити доступ багатьом користувачам до десятків облікових записів організації. Водночас на всіх рівнях застосовується принцип найменших привілеїв, що стверджує, що особам має бути дозволено лише найменший набір дій, необхідних для виконання конкретного завдання.

Grafana

Як один з інструментів логування та моніторингу ми використовуємо Prometheus & Grafana у вигляді Helm-чарта kube-prometheus-stack. Оскільки автоматизація — це запорука успіху, всі налаштування будуть проводитися в Terraform у файлі values.yaml, де власне конфігурується застосунок.

resource "helm_release" "kube_prometheus_stack" { 
 name             = "kube-prometheus-stack" 
 chart            = "kube-prometheus-stack" 
 version          = "48.3.0" 
 repository       = "https://prometheus-community.github.io/helm-charts" 
 namespace        = "monitoring" 
 create_namespace = true 
 values = [ 
   templatefile("chart_values/values.yaml", { 
     grafana_sso_client          = data.aws_secretsmanager_secret_version.grafana_sso_client_id_version.secret_string, 
     grafana_sso_secret          = data.aws_secretsmanager_secret_version.grafana_sso_client_secret_version.secret_string, 
     tenant                      = data.aws_secretsmanager_secret_version.tenant_id_version.secret_string 
   }) 
 ] 
resource "aws_secretsmanager_secret" "grafana_sso_client_id" { 
 name = "grafana_sso_client_id" 
data "aws_secretsmanager_secret" "grafana_sso_client_id_data" { 
 arn = aws_secretsmanager_secret.grafana_sso_client_id.arn 
data "aws_secretsmanager_secret_version" "grafana_sso_client_id_version" { 
 secret_id = data.aws_secretsmanager_secret.grafana_sso_client_id_data.id 
resource "aws_secretsmanager_secret" "grafana_sso_client_secret" { 
 name = "grafana_sso_client_secret" 
data "aws_secretsmanager_secret" "grafana_sso_client_secret_data" {
 arn = aws_secretsmanager_secret.grafana_sso_client_secret.arn 
data "aws_secretsmanager_secret_version" "grafana_sso_client_secret_version" { 
 secret_id = data.aws_secretsmanager_secret.grafana_sso_client_secret_data.id 
resource "aws_secretsmanager_secret" "tenant_id" { 
 name = "tenant_id" 
data "aws_secretsmanager_secret" "tenant_id_data" {
 arn = aws_secretsmanager_secret.tenant_id.arn 
data "aws_secretsmanager_secret_version" "tenant_id_version" { 
 secret_id = data.aws_secretsmanager_secret.tenant_id_data.id 

Але для того, щоб розпочати налаштування, необхідно мати групу в постачальнику ідентифікаційних даних (IdP). У нашому випадку в ролі IdP використовується Azure AD.

В Azure нам необхідно створити застосунок у тенанті нашої організації. У цій аплікації ми створюємо групу та додаємо користувачів, яким хочемо дати можливість входити до користувацького інтерфейсу (UI).

Після маніпуляцій в IdP необхідно передати значення Tenant, Client ID і Client Secret. Це зручно та безпечно робити завдяки AWS-сервісу Secrets Manager, у якому ми будемо зберігати наші значення для SSO.

Також деякі із цих значень будуть використані повторно, оскільки Tenant створюється на всю організацію і його значення не змінюється.

Технічні деталі

Створення застосунку в Azure AD. Щоб створити застосунок в Azure AD, виконайте такі дії:

  • Відкрийте портал Azure.
  • У лівому меню перейдіть до розділу Azure Active Directory.
  • У розділі Застосунки натисніть кнопку Створити застосунок.
  • У списку типів застосунків виберіть Web app/API.
  • Введіть ім’я застосунку та натисніть кнопку Створити.

Після створення застосунку Azure AD надасть вам такі значення:

  • Client ID;
  • Client Secret;
  • Tenant ID.

Зберігання значень в Secrets Manager. Щоб зберегти значення в Secrets Manager, виконайте такі дії:

  • Після виконання команди terraform apply в лівому меню консолі AWS перейдіть до розділу Secrets Manager.
  • Знайдіть новостворенний секрет.
  • У полі Значення секрету введіть відповідні значення, отримані в Azure AD.
  • Натисніть кнопку Зберегти.

Налаштування Grafana. Щоб налаштувати Grafana, виконайте такі дії:

  • Відкрийте файл values.yaml для Helm-чарта kube-prometheus-stack.
  • Знайдіть розділ grafana.
  • У полі server.auth.provider виберіть Azure AD.
  • У полі server.auth.azuread.tenantId введіть значення Tenant ID, отримане в Azure AD.
  • У полі server.auth.azuread.clientId введіть значення Client ID, отримане в Azure AD.
  • У полі server.auth.azuread.clientSecret введіть значення Client secret, отримане в Azure AD.
  • Збережіть файл values.yaml.
grafana: 
 grafana.ini: 
   auth.azuread: 
     name: Azure AD 
     enabled: true 
     allow_sign_up: true 
     auto_login: false 
     client_id: ${grafana_sso_client} 
     client_secret: ${grafana_sso_secret} 
     scopes: openid email profile 
     auth_url: https://login.microsoftonline.com/${tenant}/oauth2/v2.0/authorize 
     token_url: https://login.microsoftonline.com/${tenant}/oauth2/v2.0/token 
     allowed_organizations: ${tenant} 
     role_attribute_strict: false 
     allow_assign_grafana_admin: false 
     skip_org_role_sync: false 
     use_pkce: true 

Після виконання цих кроків Grafana буде налаштована на використання SSO з Azure AD. Користувачі, які належать до групи, створеної в Azure AD, зможуть входити до Grafana, використовуючи свої облікові записи Azure AD.

Під час входу в Grafana UI у вас зʼявиться вибір, яким способом залогінитись, й обравши Azure AD, ви авторизуєтесь, використовуючи ваш обліковий запис Microsoft.

Jenkins

Jenkins — це сервер, який підтримує концепцію Continuous Integration. Він написаний на Java, але працює з будь-якими мовами. Цей інструмент збере проєкт згідно з вашими інструкціями та виконає деплой на сервер, який ви прив’язали до нього.

Jenkins дозволяє автоматизувати частину процесу розробки програмного забезпечення без участі людини. Ця система призначена для забезпечення процесу безперервної інтеграції програмного забезпечення. Також із створенням Jenkins helm необхідно за аналогією до Grafana створити застосунок у Azure AD та секрет, у якому ми зберігаємо значення Client ID, Client Secret, Tenant ID.

resource "helm_release" "jenkins" {
name       = "jenkins"
 namespace  = var.namespace_devops
 chart      = "jenkins"
 repository = "https://charts.jenkins.io"
 values     = [templatefile("files/values/jenkins.yaml", {
    site = var.site,
    client_id = jsondecode(data.aws_secretsmanager_secret_version.jenkins_sso_secrets_version.secret_string)["Client_ID"],
    client_secret = jsondecode(data.aws_secretsmanager_secret_version.jenkins_sso_secrets_version.secret_string)["Client_Secret"],
    tenant_id = jsondecode(data.aws_secretsmanager_secret_version.jenkins_sso_secrets_version.secret_string)["Tenant_ID"]
    })]
 wait       = false
}
# Jenkins SSO secret
resource "aws_secretsmanager_secret" "jenkins_sso_secrets" {
 name = "jenkins_sso_secrets"
}
data "aws_secretsmanager_secret" "jenkins_sso_secrets_data" {
 arn = aws_secretsmanager_secret.jenkins_sso_secrets.arn
}
data "aws_secretsmanager_secret_version" "jenkins_sso_secrets_version" {
 secret_id = data.aws_secretsmanager_secret.jenkins_sso_secrets_data.id
}

Плагіни розширюють функціональність Jenkins. Їх існує тисячі, різних: від зображень з Чаком Норрісом до справді важливих речей.

Сам собою сервер порожній, і навіть Git потрібно налаштовувати через такі розширення. У цьому немає нічого складного — достатньо завантажити потрібний плагін. Припустимо, що ваш проєкт на Python і ви хочете знайти для нього розширення. Вводите ключове слово у пошуку й отримуєте список плагінів:

Для налаштування єдиного входу нам також необхідно встановити плагін Microsoft Entra ID (previously Azure AD).

Це виконується в Helm values-файлі.

Щоб не налаштовувати плагін після кожного перезапуску аплікації, важливим є нюанс: вам необхідно слідкувати за версіями плагінів, оскільки не всі вони сумісні й треба обирати, враховуючи версію самого Jenkins. У іншому разі застосунок може не запуститись або працювати некоректно.

Встановлення плагіну azure-ad та його налаштування необхідно зробити за аналогією з продемострованним кодом й передавши у змінних ваші значення Azure AD:

controller: 
 jenkinsUrl: https://jenkins.${site}
 installLatestPlugins: false
 installPlugins:
   - azure-ad:385.v5d9f88612dd2
 JCasC:
   securityRealm: |-
     azure:
       cacheDuration: 3600
       clientId: "${client_id}"
       clientSecret: "${client_secret}"
       tenant: "${tenant_id}"
   authorizationStrategy: |-
     loggedInUsersCanDoAnything:
       allowAnonymousRead: false
   configScripts:

Після прийняття змін й перестворення поду Jenkins вам необхідно буде увійти під вашим обліковим записом Microsoft. Якщо у консолі ви перейдете Dashboard > Сonfigure Jenkins > Security, то зможете побачити ваші налаштування з Azure AD, які додавались у конфігураційному файлі Jenkins Helm і завдяки яким працює SSO в цьому застосунку.

Argo CD

Argo CD став потужним та одним з основних інструментів для автоматизації розгортання застосунків і використовується багатьма організаціями, зокрема Alibaba, Cisco та Indeed. Імплементація системи єдиного входу (SSO) для Argo CD через такі популярні платформи, як-от Microsoft, Google, Auth0 та інші IdP, покликане спростити роботу DevOps-інженера або розробника та підвищити безпеку доступу.

У контексті єдиного входу в Argo CD, Dex займає центральне місце як постачальник ідентифікації та автентифікації з відкритим кодом. Він відіграє ключову роль у з’єднанні ваших застосунків з різноманітними постачальниками ідентифікаційної інформації, такими як LDAP, SAML і OAuth2, одночасно реалізуючи основний протокол OpenID Connect (OIDC).

Важливо, що коли ви вирішуєте встановити Argo CD за допомогою діаграми Helm або маніфесту YAML, Dex постачається в комплекті, що спрощує налаштування безперебійної функції єдиного входу. Щоб налаштувати єдиний вхід для Argo CD, вам необхідно створити застосунок в Azure AD і отримати значення Client ID, Tenant ID та CaCert.

Після цього ви можете налаштувати конфігурацію Argo CD, використовуючи наступні кроки.

Створіть конфігурацію Helm, як у прикладі нижче:

resource "helm_release" "argocd" {
 name             = "argo-cd"
 repository       = "https://argoproj.github.io/argo-helm"
 chart            = "argo-cd"
 namespace        = "argocd"
 version          = "5.43.3"
 create_namespace = true
 reset_values     = true
 values = [templatefile("files/values/argocd.yaml", {
   argocd_site_name = local.argocd_site_name,
   argocd_sso_certificate = data.aws_secretsmanager_secret_version.argocd_sso_certificate_version.secret_string,
   argocd_sso_url = jsondecode(data.aws_secretsmanager_secret_version.argocd_sso_version.secret_string)["SSO_URL"],
   argocd_sso_group = jsondecode(data.aws_secretsmanager_secret_version.argocd_sso_version.secret_string)["USER_GROUP"]
 })]
}

Створіть секрети в AWS Secrets Manager, які містять значення Client ID, Tenant ID та CaCert.

# ArgoCD SSO secrets
resource "aws_secretsmanager_secret" "argocd_sso" {
 name = "argocd_sso"
}
data "aws_secretsmanager_secret" "argocd_sso_data" {
 arn = aws_secretsmanager_secret.argocd_sso.arn
}
data "aws_secretsmanager_secret_version" "argocd_sso_version" {
 secret_id = data.aws_secretsmanager_secret.argocd_sso_data.id
}
resource "aws_secretsmanager_secret" "argocd_sso_certificate" {
 name = "argocd_sso_certificate"
}
data "aws_secretsmanager_secret" "argocd_sso_certificate_data" {
 arn = aws_secretsmanager_secret.argocd_sso_certificate.arn
}
data "aws_secretsmanager_secret_version" "argocd_sso_certificate_version" {
 secret_id = data.aws_secretsmanager_secret.argocd_sso_certificate_data.id
}

Налаштуйте конфігурацію Argo CD, використовуючи такі параметри:

  • argocd_site_name: Ім’я вебсайту (Host) Argo CD.
  • argocd_sso_certificate: Кодований у Base64 сертифікат підпису SAML.
  • argocd_sso_url: URL-адреса служби єдиного входу.
  • argocd_sso_group: ID групи користувачів, яким надається доступ до Argo CD.

3.1 Налаштуйте права доступу користувачам, яким надаєте доступ до Argo CD.

configs:
 cm:
   create: true
   url: https://${argocd_site_name}
   dex.config: |
     logger:
       level: debug
       format: json
     connectors:
     - type: saml
       id: saml
       name: saml
       config:
         entityIssuer: https://${argocd_site_name}/api/dex/callback
         ssoURL: ${argocd_sso_url}
         caData: |
           ${argocd_sso_certificate}
         redirectURI: https://${argocd_site_name}/api/dex/callback
         usernameAttr: email
         emailAttr: email
         groupsAttr: Group
 rbac:
   create: true
   policy.csv: |
     p, role:devops, applications, *, */*, allow
     p, role:devops, clusters, get, *, allow
     p, role:devops, repositories, get, *, allow
     p, role:devops, repositories, create, *, allow
     p, role:devops, repositories, update, *, allow
     p, role:devops, projects, get, *, allow
     p, role:devops, projects, create, *, allow
     p, role:devops, projects, update, *, allow
     p, role:devops, logs, get, *, allow
     p, role:devops, exec, create, */*, allow
     g, "${argocd_sso_group}", role:devops

Після конфігурації Argo CD Helm під час спроби ввійти у застосунок у вас зʼявиться альтернативний варіант входу, використовуючи SAML.

Amazon EKS

Щоб налаштувати SSO в інфраструктурі Kubernetes, дотримуйтесь наведених нижче кроків, які детально описують конфігурацію Terraform, необхідну для реалізації OIDC у нашому кластері EKS. Додамо ресурс постачальника ідентифікаційної інформації:

resource "aws_eks_identity_provider_config" "eks_identity_provider" {
 cluster_name = terraform.workspace
 oidc {
   client_id                     = jsondecode(data.aws_secretsmanager_secret_version.eks_sso_secret_version.secret_string)["CLIENT_ID"]
   groups_claim                  = "groups"
   groups_prefix                 = "aad:"
   identity_provider_config_name = "AzureAD"
   issuer_url                    = "https://sts.windows.net/${data.aws_secretsmanager_secret_version.tenant_id_version.secret_string}/"
   username_claim                = "upn"
   username_prefix               = "aad:"
 }
 timeouts {
   create = "2h"
   delete = "2h"
 }
}

Тайм-аути тут є важливими, тому що стандартні параметри здавалися недостатньо довгими для успішного завершення конфігурації. Тепер нам потрібно додати ClusterRoleBindings або RoleBindings до кластера, щоб після автентифікації користувачі мали доступ для взаємодії з кластером, приклад чого можна побачити нижче.

# Cluster role for developers
resource "kubernetes_cluster_role" "dev" 
 metadata {
   name = "dev"
 }
 rule {
   api_groups = ["*"]
   resources  = ["*"]
   verbs      = ["get", "list", "watch"]
 }
}
# Cluster role binding for Azure users
resource "kubernetes_cluster_role_binding" "sso_dev_users_cluster_role_binding" {
 metadata {
   name = "sso-dev"
 }
 role_ref {
   api_group = "rbac.authorization.k8s.io"
   kind      = "ClusterRole"
   name      = "dev"
 }
 subject {
   api_group = "rbac.authorization.k8s.io"
   kind      = "Group"
   name      = "aad:${local.dev-sso-group}"
 }
}

Перед назвою групи має бути префікс aad, щоб відповідати префіксу, який ми додали як частину конфігурації EKS у рядку з username_prefix цієї реалізації. Гарною практикою є перед будь-якими прив’язками ClusterRole/Role додати ім’я, яке ви запам’ятаєте, щоб спершу об’єднати всі прив’язки разом під час їх переліку, а також зробити очевидним, що ви повинні використовувати SSO, щоб використовувати їх.

Для автентифікації ми використовуємо kubelogin. Перш за все потрібно встановити плагін kubectl krew install oidc-login.

По-друге, вам потрібно автентифікуватись за допомогою такої команди:

kubectl oidc-login setup \
--oidc-issuer-url https://sts.windows.net/<Tenant ID>/ \
--oidc-client-id CLIENT_ID \
--oidc-client-secret CLIENT_SECRET

Наведена вище команда виводить ваш маркер JWT для підтвердження того, що ви успішно пройшли автентифікацію в Azure. Далі вам потрібно додати до вашого файлу kubeconfig, розташованого за адресою ~/.kube/config:

apiVersion: v1
kind: Config
clusters:
 - name: arn:aws:eks:<aws_region>:<aws_acc_id>:cluster/<cluster_name>
   cluster:
     server: https://***.gr7.<aws_region>.eks.amazonaws.com
     certificate-authority-data: >-
       ***
     insecure-skip-tls-verify: false
users:
 - name: oidc
   user:
     exec:
       apiVersion: client.authentication.k8s.io/v1beta1
       args:
         - oidc-login
         - get-token
         - >-
           --oidc-issuer-url=https://sts.windows.net/<Tenant ID>/
         - '--oidc-client-id=<CLIENT_ID>'
         - '--oidc-client-secret=<CLIENT_SECRET>'
       command: kubectl
       env: null
       interactiveMode: IfAvailable
       provideClusterInfo: false
contexts: []
preferences: {}
current-context: arn:aws:eks:<aws_region>:<aws_acc_id>:cluster/<cluster_name>

Щоб впевнитися, що нова конфігурація працює, можемо звернутись до кластера командою по типу kubectl --user=oidc get nodes. Після того, як ви впевнились, що у вас все працює та ви підключили всіх необхдних користувачів до кластеру, додавши їх у відведену для цього групу, можете видалити їх IAM користувачів з кластеру.

Amazon Web Services

AWS пропонує кілька способів налаштувати єдиний вхід для своїх послуг. Один з них — використовувати службу AWS Identity and Access Management (IAM) для створення ролей і прив’язок ролей, які надають користувачам доступ до певних ресурсів AWS.

Інший спосіб (основний) — використовувати постачальника ідентифікаційної інформації (IdP), такий як Azure AD або Okta, для аутентифікації користувачів і надання їм доступу до ресурсів AWS. Для нашого способу підʼєднання нам знадобиться root-акаунт організації, бо саме в ньому будуть відбуватися налаштування Single Sign-On на стороні AWS і саме з нього регулюється рівень доступу до інших акаунтів організації.

Перш за все необхідно в Microsoft Azure зайти в Azure AD, створити Enterprice application і додати в нього групи з користувачами.

Створивши застосунок для AWS у вкладці Single Sign-on, потрібно завантажити Federation Metadata XML, який нам знадобиться для IAM Identity Center. У головному акаунті організації переходимо до IAM Identity Center і вмикаємо його, натискаючи на відповідну кнопку.

Увімкнувши IAM Identity Center в головному акаунті організації, наступним кроком необхідно перейти в налаштування й у вкладці Choose identity source обрати пункт External identity provider.

Далі необхідно обмінятись SAML metadata між AWS і Azure AD, для чого додаємо Federation Metadata XML у консолі AWS й зберігаємо файл Service provider metadata, щоб потім перенести його у додаток, створенний в Azure AD.

Також для автоматизованої синхронізації користувачів між Azure AD і AWS потрібно у налаштуваннях IAM Identity Center у пункті Provisioning увімкнути автоматичну синхронізацію, скопіювавши SCIM endpoint й Access token, щоб додати його до аплікації в Microsoft Azure.

Перейшовши до Microsoft Azure в аплікації, яка створена для AWS у вкладці Single Sign-on, потрібно загрузити раніше встановлений Service provider metadata. Щоб увімкнути автоматичну синхронізацію, перемикаємо режим на автоматичний, вставляємо раніше скопійовані значення SCIM endpoint й Access token і натискаємо кнопку Test connection. Якщо на рівні з полями значень ви бачите відповідні галочки, значить зʼєднання встановлене.

Отже тепер SSO налаштоване, й у мірі додавання груп та користувачів до цієї аплікації вони будуть автоматично переноситись й в AWS IAM Identity Center.

Без змін цей механізм працює з видаленням, тобто, якщо користувача прибрати в Azure AD, за наступної синхронізації він видалиться. Автоматична синхронізація працює з деякою періодичністю, тож щоб зміни синхронізувалися, потрібно або зачекати, або провести синхронізацію власноруч, якщо це терміново.

Як тільки в консолі у вас зʼявились групи й користувачі, можете переходити до налаштування доступу, памʼятаючи про принцип найменших привілеїв під час розподілення ролей й доступів до акаунтів. Також гарною практикою є зменшення часу дії токену, який надається користувачу під час аутентифікації.

Перевіривши ролі й інші конфігурації, тепер можна відмовитись від використання IAM користувачів в акаунтах вашої організації, що значно покращує рівень безпеки інфраструктури, централізує керування обліковими записами й полегшує комунікацію у вашій команді, замінивши десятки паролів й відповідних MFA на один логін і пароль від пошти та відповідний двофакторний аутентифікатор.

👍ПодобаєтьсяСподобалось2
До обраногоВ обраному3
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Трошки занудство, але хіба AD не перевзулося в Entra ID ?
І ще з цікавого- якщо уже є одна хмара у вигляді Ажур, чому розгортаються застосунки на Амазоні?

хіба AD не перевзулося в Entra ID ?

Application Registration\Enterprise App це ж воно і є? хіба ні?

якщо уже є одна хмара у вигляді Ажур, чому розгортаються застосунки на Амазоні?

теж як на мене трішки дивно. Ну може вони з Ажура тільки AAD юзають і не хочуть платити за AKS

Ми партнери Амазона і амазон нам гарну знижку та багато кредитів накинув.

А з технічної сторони ми не проти перейти в AKS (там якраз вже і карпентер підтримується)

Наразі ми співпрацюємо з Амазоном, оскільки маємо отримали спеціальні умови, такі як знижки та кредити, а використовуємо тільки AAD (нова назва — Microsoft Entra ID) в Ажурі. Взагалі є можливість використовувати будь-який Identity Provider (IdP), підключення буде виглядати схожим чином

Підписатись на коментарі