Поделиться через


Использование расширения Secret Store для получения секретов для автономного доступа в кластерах Kubernetes с поддержкой Azure Arc

Расширение хранилища секретов Azure Key Vault для Kubernetes ("SSE") автоматически синхронизирует секреты из Azure Key Vault с кластером Kubernetes с поддержкой Azure Arc для автономного доступа. Это означает, что Azure Key Vault можно использовать для хранения, обслуживания и смены секретов даже когда вы запускаете кластер Kubernetes в условиях частичного отключения. Синхронизированные секреты хранятся в хранилище секретов кластера, что делает их доступными в качестве секретов Kubernetes, которые могут использоваться всеми обычными способами: монтироваться как тома данных или предоставляться в виде переменных среды для контейнера в pod.

Синхронизированные секреты являются критически важными бизнес-ресурсами, поэтому служба SSE защищает их с помощью изолированных пространств имен и узлов, политик управления доступом на основе ролей (RBAC) и ограниченных разрешений для синхронизатора секретов. Для дополнительной защиты зашифруйте хранилище секретов Kubernetes в кластере.

Подсказка

SSE рекомендуется для сценариев, когда требуется автономный доступ, или если вам нужны секреты, синхронизированные с хранилищем секретов Kubernetes. Если эти функции не нужны, вы можете использовать расширение поставщика секретов Azure Key Vault для управления секретами в кластерах Kubernetes с поддержкой Arc. Не рекомендуется запускать онлайн-расширение поставщика секретов Azure Key Vault и офлайн-SSE параллельно в кластере.

В этой статье показано, как установить и настроить SSE в качестве расширения Kubernetes с поддержкой Azure Arc.

Это важно

В настоящее время SSE находится в предварительной версии. Ознакомьтесь с Дополнительными условиями использования для предварительных версий Microsoft Azure, чтобы узнать юридические условия, применимые к функциям Azure, которые находятся в статусе бета, предварительного просмотра или иначе еще не выпущены в общий доступ.

Предпосылки

  • Кластер с поддержкой Arc. Это может быть кластер, который вы настроили самостоятельно (в примерах этого руководства используется кластер K3s), или управляемый корпорацией Майкрософт кластер AKS, активированный с помощью Azure Arc. Кластер должен работать под управлением Kubernetes версии 1.27 или выше.
  • Убедитесь, что выполнены общие предварительные требования для расширенийk8s-extension кластера, включая последнюю версию расширения Azure CLI.
  • cert-manager необходим для поддержки TLS в целях внутрикластерного обмена журналами. Примеры в этом руководстве помогут вам пройти через процесс установки. Дополнительные сведения о диспетчере сертификатов см. в cert-manager.io

Установите Azure CLI и выполните вход, если вы еще не выполнили следующие действия.

az login

Прежде чем начать, задайте переменные среды для настройки ресурсов Azure и кластера. Если у вас уже есть управляемое удостоверение, например, Azure Key Vault или другой ресурс, указанный здесь, обновите имена в переменных среды, чтобы отразить эти ресурсы. Обратите внимание, что KEYVAULT_NAME должно быть глобально уникальным; создание keyvault завершится сбоем позже, если это имя уже используется в Azure.

export RESOURCE_GROUP="AzureArcTest"
export CLUSTER_NAME="AzureArcTest1"
export LOCATION="EastUS"
export SUBSCRIPTION="$(az account show --query id --output tsv)"
az account set --subscription "${SUBSCRIPTION}"
export AZURE_TENANT_ID="$(az account show -s $SUBSCRIPTION --query tenantId --output tsv)"
export CURRENT_USER="$(az ad signed-in-user show --query userPrincipalName --output tsv)"
export KEYVAULT_NAME="my-UNIQUE-kv-name"
export KEYVAULT_SECRET_NAME="my-secret"
export USER_ASSIGNED_IDENTITY_NAME="my-identity"
export FEDERATED_IDENTITY_CREDENTIAL_NAME="my-credential"
export KUBERNETES_NAMESPACE="my-namespace"
export SERVICE_ACCOUNT_NAME="my-service-account"

Активируйте федерацию удостоверений рабочих нагрузок в вашем кластере

Служба SSE использует функцию, называемую федерацией идентификации нагрузки, для доступа к секретам Azure Key Vault и их синхронизации. В этом разделе описывается настройка функции. В следующих разделах описано, как оно используется подробно.

Подсказка

Следующие шаги основаны на практическом руководстве по настройке Kubernetes с поддержкой Arc и федерацией удостоверений рабочей нагрузки. Дополнительные сведения см. в этой документации.

Если кластер еще не подключен к Azure Arc, выполните следующие действия. В ходе этих действий включите федерацию удостоверений рабочей нагрузки connect в рамках команды:

az connectedk8s connect --name ${CLUSTER_NAME} --resource-group ${RESOURCE_GROUP} --enable-oidc-issuer

Для включения удостоверения рабочей нагрузки, если ваш кластер уже подключен к Azure Arc, используйте команду update.

az connectedk8s update --name ${CLUSTER_NAME} --resource-group ${RESOURCE_GROUP} --enable-oidc-issuer

Теперь настройте кластер для выдачи маркеров учетной записи службы с новым URL-адресом издателя (service-account-issuer), который позволяет Microsoft Entra ID найти открытые ключи, необходимые для проверки этих маркеров. Эти открытые ключи предназначены для издателя токенов учетной записи службы самого кластера и были получены и размещены в облаке по этому URL-адресу в результате ранее установленного параметра --enable-oidc-issuer.

При необходимости можно также настроить ограничения на собственные разрешения SSE в качестве привилегированного ресурса, работающего в плоскости управления, настроив OwnerReferencesPermissionEnforcementконтроллер допуска. Этот контроллер допуска ограничивает, сколько SSE может изменить другие объекты в кластере.

  1. Настройте kube-apiserver с полем URL-адреса издателя и принудительным соблюдением разрешений. В следующем примере используется кластер k3s. Ваш кластер может иметь разные средства для изменения аргументов сервера API: --kube-apiserver-arg="--service-account-issuer=${SERVICE_ACCOUNT_ISSUER}" and --kube-apiserver-arg="--enable-admission-plugins=OwnerReferencesPermissionEnforcement"

    • Получите URL-адрес издателя учетной записи службы.

      export SERVICE_ACCOUNT_ISSUER="$(az connectedk8s show --name ${CLUSTER_NAME} --resource-group ${RESOURCE_GROUP} --query "oidcIssuerProfile.issuerUrl" --output tsv)"
      echo $SERVICE_ACCOUNT_ISSUER
      
    • Откройте файл конфигурации сервера K3s.

      sudo nano /etc/systemd/system/k3s.service
      
    • Измените конфигурацию сервера как в следующем примере, заменив <SERVICE_ACCOUNT_ISSUER> предыдущим выводом из echo $SERVICE_ACCOUNT_ISSUER, не забывая включить конечную косую черту этого URL-адреса.

      ExecStart=/usr/local/bin/k3s \
        server --write-kubeconfig-mode=644 \
           --kube-apiserver-arg="--service-account-issuer=<SERVICE_ACCOUNT_ISSUER>" \
           --kube-apiserver-arg="--enable-admission-plugins=OwnerReferencesPermissionEnforcement"
      
  2. Перезапустите kube-apiserver.

    sudo systemctl daemon-reload
    sudo systemctl restart k3s
    

Создание секрета и настройка удостоверения для доступа к нему

Чтобы сервис SSE получил доступ к заданному секрету Azure Key Vault и синхронизировал его, необходим доступ к управляемому удостоверению Azure с соответствующими разрешениями для доступа к этому секрету. Управляемое удостоверение должно быть связано с учетной записью службы Kubernetes с помощью функции удостоверения рабочей нагрузки, активированной ранее. Служба SSE использует ассоциированную федеративную управляемую идентичность Azure для извлечения секретов из Azure Key Vault в секретное хранилище Kubernetes. В следующих разделах описано, как настроить эту настройку.

Создание Azure Key Vault

Создайте Azure Key Vault и добавьте секрет. Если у вас уже есть Azure Key Vault и секрет, этот раздел можно пропустить.

  1. Создайте Azure Key Vault:

    az keyvault create --resource-group "${RESOURCE_GROUP}" --location "${LOCATION}" --name "${KEYVAULT_NAME}" --enable-rbac-authorization
    
  2. Назначьте себе права "администратор секретов" в хранилище, чтобы создать секрет:

    az role assignment create --role "Key Vault Secrets Officer" --assignee ${CURRENT_USER} --scope /subscriptions/${SUBSCRIPTION}/resourcegroups/${RESOURCE_GROUP}/providers/Microsoft.KeyVault/vaults/${KEYVAULT_NAME}
    
  3. Создайте секрет и обновите его, чтобы иметь две версии:

    az keyvault secret set --vault-name "${KEYVAULT_NAME}" --name "${KEYVAULT_SECRET_NAME}" --value 'Hello!'
    az keyvault secret set --vault-name "${KEYVAULT_NAME}" --name "${KEYVAULT_SECRET_NAME}" --value 'Hello2'
    

Создание управляемой идентичности, назначаемой пользователем

Затем создайте управляемое удостоверение, назначаемое пользователем, и предоставьте ему разрешения на доступ к Azure Key Vault. Если у вас уже есть управляемое удостоверение с разрешениями "Key Vault Reader" и "Key Vault Secrets User" в Azure Key Vault, можно пропустить этот раздел. Дополнительные сведения см. в статье "Создание управляемых удостоверений, назначаемых пользователем" и Использование разрешений на секреты, ключи и сертификаты Azure RBAC с Key Vault.

  1. Создайте назначаемое пользователем управляемое удостоверение:

    az identity create --name "${USER_ASSIGNED_IDENTITY_NAME}" --resource-group "${RESOURCE_GROUP}" --location "${LOCATION}" --subscription "${SUBSCRIPTION}"
    
  2. Предоставьте удостоверению разрешение пользователя Key Vault Reader и Key Vault Secret User. Возможно, потребуется подождать некоторое время, пока не завершится репликация создания удостоверения, прежде чем эти команды будут выполнены успешно.

    export USER_ASSIGNED_CLIENT_ID="$(az identity show --resource-group "${RESOURCE_GROUP}" --name "${USER_ASSIGNED_IDENTITY_NAME}" --query 'clientId' -otsv)"
    az role assignment create --role "Key Vault Reader" --assignee "${USER_ASSIGNED_CLIENT_ID}" --scope /subscriptions/${SUBSCRIPTION}/resourcegroups/${RESOURCE_GROUP}/providers/Microsoft.KeyVault/vaults/${KEYVAULT_NAME}
    az role assignment create --role "Key Vault Secrets User" --assignee "${USER_ASSIGNED_CLIENT_ID}" --scope /subscriptions/${SUBSCRIPTION}/resourcegroups/${RESOURCE_GROUP}/providers/Microsoft.KeyVault/vaults/${KEYVAULT_NAME}
    

Создать учетные данные для федеративной идентичности

Создайте учетную запись службы Kubernetes для рабочей нагрузки, требующей доступа к секретам. Затем создайте федеративные учетные данные удостоверения для связи между управляемым удостоверением, издателем учетной записи службы OIDC и учетной записью службы Kubernetes.

  1. Создайте учетную запись службы Kubernetes, которая будет федерально связана с управляемым удостоверением. Заметите его с подробными сведениями о связанном управляемом удостоверении, назначаемом пользователем.

    kubectl create ns ${KUBERNETES_NAMESPACE}
    
    cat <<EOF | kubectl apply -f -
      apiVersion: v1
      kind: ServiceAccount
      metadata:
        name: ${SERVICE_ACCOUNT_NAME}
        namespace: ${KUBERNETES_NAMESPACE}
    EOF
    
  2. Создайте учетные данные федеративного удостоверения:

    az identity federated-credential create --name ${FEDERATED_IDENTITY_CREDENTIAL_NAME} --identity-name ${USER_ASSIGNED_IDENTITY_NAME} --resource-group ${RESOURCE_GROUP} --issuer ${SERVICE_ACCOUNT_ISSUER} --subject system:serviceaccount:${KUBERNETES_NAMESPACE}:${SERVICE_ACCOUNT_NAME} --audience api://AzureADTokenExchange
    

Установка SSE

Служба SSE доступна как расширение Azure Arc. Кластер Kubernetes с поддержкой Azure Arc можно расширить с помощью расширений Kubernetes с поддержкой Azure Arc. Расширения обеспечивают возможности Azure в подключенном кластере и предоставляют управляемый Azure Resource Manager интерфейс для установки и управления жизненным циклом расширений.

Диспетчер сертификатов и диспетчер доверия также требуются для безопасного взаимодействия журналов между службами кластера и должны быть установлены перед расширением Arc.

  1. Установите cert-manager.

    helm repo add jetstack https://charts.jetstack.io/ --force-update
    helm install cert-manager jetstack/cert-manager --namespace cert-manager --create-namespace --version v1.16.2 --set crds.enabled=true 
    
  2. Установите диспетчер доверия.

    helm upgrade trust-manager jetstack/trust-manager --install --namespace cert-manager --wait
    
  3. Установите SSE в кластер с поддержкой Arc, выполнив следующую команду:

    az k8s-extension create \
      --cluster-name ${CLUSTER_NAME} \
      --cluster-type connectedClusters \
      --extension-type microsoft.azure.secretstore \
      --resource-group ${RESOURCE_GROUP} \
      --release-train preview \
      --name ssarcextension \
      --scope cluster 
    

    При необходимости можно изменить интервал опроса поворота по умолчанию, добавив --configuration-settings rotationPollIntervalInSeconds=<time_in_seconds>:

    Имя параметра Описание Значение по умолчанию
    rotationPollIntervalInSeconds Указывает, как быстро SSE проверяет или обновляет секрет, которым он управляет. 3600 (1 час)

Настройка SSE

Настройте установленное расширение с информацией о Azure Key Vault и секретах для синхронизации с кластером, определив экземпляры пользовательских ресурсов Kubernetes. Вы создаете два типа пользовательских ресурсов:

  • SecretProviderClass Объект, определяющий подключение к Key Vault.
  • SecretSync Объект для синхронизации каждого секрета.

Создайте SecretProviderClass ресурс

Ресурс SecretProviderClass используется для определения подключения к Azure Key Vault, удостоверения, используемого для доступа к хранилищу, секретов для синхронизации и количества версий каждого секрета для хранения локально.

Для каждого Azure Key Vault, для каждого удостоверения, используемого для доступа к Azure Key Vault, и для каждого целевого пространства имен Kubernetes необходимо иметь отдельное SecretProviderClass.

Создайте один или несколько SecretProviderClass файлов YAML с соответствующими для хранилища ключей и секретов значениями, следуя этому примеру.

cat <<EOF > spc.yaml
apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
  name: secret-provider-class-name                      # Name of the class; must be unique per Kubernetes namespace
  namespace: ${KUBERNETES_NAMESPACE}                    # Kubernetes namespace to make the secrets accessible in
spec:
  provider: azure
  parameters:
    clientID: "${USER_ASSIGNED_CLIENT_ID}"               # Managed Identity Client ID for accessing the Azure Key Vault with.
    keyvaultName: ${KEYVAULT_NAME}                       # The name of the Azure Key Vault to synchronize secrets from.
    objects: |
      array:
        - |
          objectName: ${KEYVAULT_SECRET_NAME}            # The name of the secret to synchronize.
          objectType: secret
          objectVersionHistory: 2                       # [optional] The number of versions to synchronize, starting from latest.
    tenantID: "${AZURE_TENANT_ID}"                       # The tenant ID of the Key Vault 
EOF

SecretSync Создание объекта

Объект SecretSync необходим для определения того, как элементы, извлекаемые SecretsProviderClass, хранятся в Kubernetes. Секреты Kubernetes — это карты с ключом-значением, как ConfigMaps, а объект SecretSync сообщает SSE, как сопоставить элементы, определенные в связанном SecretsProviderClass, с ключами в секрете Kubernetes. SSE создаст секрет Kubernetes с тем же именем, что и SecretSync, описывающий его.

Создайте один SecretSync файл YAML объекта для каждого секрета Kubernetes, следуя этому шаблону. Пространство имен Kubernetes должно соответствовать пространству имен соответствующего SecretProviderClass.

cat <<EOF > ss.yaml
apiVersion: secret-sync.x-k8s.io/v1alpha1
kind: SecretSync
metadata:
  name: secret-sync-name                                  # Name of the object; must be unique per Kubernetes namespace
  namespace: ${KUBERNETES_NAMESPACE}                      # Kubernetes namespace
spec:
  serviceAccountName: ${SERVICE_ACCOUNT_NAME}             # The Kubernetes service account to be given permissions to access the secret.
  secretProviderClassName: secret-provider-class-name     # The name of the matching SecretProviderClass with the configuration to access the AKV storing this secret
  secretObject:
    type: Opaque
    data:
    - sourcePath: ${KEYVAULT_SECRET_NAME}/0                # Name of the secret in Azure Key Vault with an optional version number (defaults to latest)
      targetKey: ${KEYVAULT_SECRET_NAME}-data-key0         # Target name of the secret in the Kubernetes secret store (must be unique)
    - sourcePath: ${KEYVAULT_SECRET_NAME}/1                # [optional] Next version of the AKV secret. Note that versions of the secret must match the configured objectVersionHistory in the secrets provider class 
      targetKey: ${KEYVAULT_SECRET_NAME}-data-key1         # [optional] Next target name of the secret in the K8s secret store
EOF

Подсказка

Не включайте "/0" при упоминании секрета из SecretProviderClass где objectVersionHistory< 2. Последняя версия используется неявно.

Примените CR конфигурации

Примените настраиваемые ресурсы конфигурации (CR) с помощью kubectl apply команды:

kubectl apply -f ./spc.yaml
kubectl apply -f ./ss.yaml

Служба SSE автоматически ищет секреты и начинает синхронизацию их с кластером.

Просмотр параметров конфигурации

Чтобы просмотреть дополнительные параметры конфигурации для этих двух пользовательских типов ресурсов, используйте kubectl describe команду для проверки CRD в кластере.

# Get the name of any applied CRD(s)
kubectl get crds -o custom-columns=NAME:.metadata.name

# View the full configuration options and field parameters for a given CRD
kubectl describe crd secretproviderclass
kubectl describe crd secretsync

Наблюдение за синхронизацией секретов с кластером

После применения конфигурации секреты начинают синхронизироваться с кластером автоматически с частотой, указанной при установке SSE.

Просмотр синхронизированных секретов

Просмотрите секреты, синхронизированные с кластером, выполнив следующую команду:

# View a list of all secrets in the namespace
kubectl get secrets -n ${KUBERNETES_NAMESPACE}

# View details of all secrets in the namespace
kubectl get secrets -n ${KUBERNETES_NAMESPACE} -o yaml

Просмотр состояния последней синхронизации

Чтобы просмотреть состояние последней синхронизации для заданного секрета, используйте kubectl describe команду для SecretSync объекта. Выходные данные включают метку времени создания секрета, версии секрета и подробные сообщения о состоянии для каждого события синхронизации. Эти выходные данные можно использовать для диагностики ошибок подключения или конфигурации, а также для наблюдения за изменением значения секрета.

kubectl describe secretsync secret-sync-name -n ${KUBERNETES_NAMESPACE}

Просмотр значений секретов

Чтобы просмотреть синхронизированные значения секретов, теперь хранящиеся в хранилище секретов Kubernetes, выполните следующую команду:

kubectl get secret secret-sync-name -n ${KUBERNETES_NAMESPACE} -o jsonpath="{.data.${KEYVAULT_SECRET_NAME}-data-key0}" | base64 -d
kubectl get secret secret-sync-name -n ${KUBERNETES_NAMESPACE} -o jsonpath="{.data.${KEYVAULT_SECRET_NAME}-data-key1}" | base64 -d

Устранение неполадок

SSE — это развертывание Kubernetes, содержащее pod с двумя контейнерами: контроллер, управляющий хранением секретов в кластере, и провайдер, контролирующий доступ к Azure Key Vault и извлечение секретов из него. Каждый синхронизированный SecretSync секрет содержит объект, содержащий состояние синхронизации этого секрета из Azure Key Vault в хранилище секретов кластера.

Чтобы устранить проблему, начните с просмотра состояния объекта, как описано в SecretSync синхронизации. В следующей таблице перечислены распространенные причины состояния, их значения и возможные действия по устранению ошибок.

Причина состояния SecretSync Сведения Шаги для исправления/дальнейшего исследования
UpdateNoValueChangeSucceeded Секрет в Kubernetes полностью up-to-date to the AKV version. Изменения не были необходимы во время последней проверки. n/a
UpdateValueChangeOrForceUpdateSucceeded Весь секрет в Kubernetes был успешно обновлен до версии AKV во время последней проверки. n/a
PartialSync Не удалось обновить некоторые элементы в секретной информации. Изучите подробнее, посмотрев в status.conditions.message поле объекта SecretSync. Это поле будет содержать сводку в строковом формате в формате JSON об успешном выполнении или сбое для каждого элемента в секрете.
ProviderError Сбой создания секрета из-за некоторых проблем с поставщиком (подключение к Azure Key Vault). Эта ошибка может быть вызвана подключением к Интернету, недостаточными разрешениями для секретов синхронизации удостоверений, неправильной настройки SecretProviderClassили других проблем. Сначала расследуйте, как с PartialSync, затем изучите журналы поставщика, используя следующие команды.
kubectl get pods -n azure-secret-store
kubectl logs <secret-sync-controller-pod-name> -n azure-secret-store --container='provider-azure-installer'
InvalidClusterSecretLabelError
InvalidClusterSecretAnnotationError
Секрет уже существует с таким именем, который не управляется службой SSE. Удалите секрет, чтобы разрешить SSE повторно создать секрет: kubectl delete secret <secret-name>
Чтобы заставить SSE воссоздать секрет быстрее, чем заданный интервал опроса ротации, удалите объект SecretSync (kubectl delete secretsync <secret-name>) и повторно примените класс синхронизации секрета kubectl apply -f <path_to_secret_sync>.
UserInputValidationFailed Сбой обновления секрета, так как класс синхронизации секретов настроен неправильно (например, недопустимый тип секрета). Просмотрите определение класса "secret sync" и исправьте все ошибки. Затем удалите объект (SecretSync), удалите класс синхронизации секретов (kubectl delete secretsync <secret-name>), и повторно примените класс синхронизации секретов (kubectl delete -f <path_to_secret_sync>).
ControllerSpcError Сбой обновления секрета, поскольку SSE не удалось получить класс поставщика или класс поставщика настроен неверно. Проверьте класс поставщика и исправьте все ошибки. Затем удалите объект (SecretSync), удалите класс поставщика (kubectl delete secretsync <secret-name>) и повторно примените класс поставщика (kubectl delete -f <path_to_provider>).
ControllerInternalError
ValidatingAdmissionPolicyCheckFailed
ControllerSyncFailed
Сбой обновления секрета из-за внутренней ошибки в SSE. Дополнительные сведения см. в журналах SSE или событиях.
kubectl get pods -n azure-secret-store
kubectl logs <secret-sync-controller-pod-name> -n azure-secret-store --container='manager'
UnknownError Сбой обновления секрета при изменении значения секрета в Kubernetes. Эта ошибка может произойти, если секрет был изменен кем-либо, кроме SSE, или если во время обновления SSE возникли проблемы. Попробуйте удалить секрет и SecretSync объект, а затем разрешить SSE повторно создать секрет, повторно применив SecretSync объект:
kubectl delete secret <secret-name>
kubectl delete secretsync <secret-name>
kubectl apply -f <path_to_secret_sync>
Если это не поможет, выполните действия для проверки журналов аналогично тому, как с ControllerInternalError.

Удалите SSE

Чтобы удалить SSE и прекратить синхронизацию секретов, используйте команду az k8s-extension delete для удаления.

az k8s-extension delete --name ssarcextension --cluster-name $CLUSTER_NAME  --resource-group $RESOURCE_GROUP  --cluster-type connectedClusters    

Удаление расширения не удаляет секреты, SecretSync объекты или CRD из кластера. Эти объекты должны быть удалены напрямую с помощью kubectl.

При удалении CRD SecretSync удаляются все объекты SecretSync, и по умолчанию удаляются все принадлежащие им секреты, но секреты могут сохраниться в следующих случаях:

В этих случаях секреты необходимо удалить напрямую с помощью kubectl.

Дальнейшие шаги