Предисловие
Часто на проектах встречается проблема безопасного хранения секретной информации, такой как, логин и пароль от какой-либо системы, используемой в рамках интеграций. Для таких случаев можно воспользоваться секретами Kubernetes и в нужный момент из них извлекать необходимые данных. Далее рассмотрим как это сделать.
Ограничения
- Только для On-Premises
- При включении и выключении Пользовательского модуля ELMA365, придется заново вносить изменения в deployment переносимого сервиса
Инструкция
Рассмотрим механизм хранения секретов на примере ELMA365 On-Premises Standard, установку которой можно выполнить согласно статье.
- Для начала создадим файл с секретами auth.secrets.json и расположим его, например, по пути /backup/auth.secrets.json
Код:
{
"Database": {
"ConnectionString": "Secret from kubernetes!!!"
}
}
- Создадим секрет auth-secrets в пространстве имен elma365-applets на основе файла auth.secrets.json с помощью следующей команды
Код:
docker exec elma365 kubectl -n elma365-applets create secret generic auth-secrets --from-file=/backup/auth.secrets.json
- Следующим шагом создадим Пользовательский модуль ELMA365 для которого подключим сервис EleWise.ELMA365.Service.Secrets, образ которого расположен по ссылке. При подключении сервиса следует указать следующие параметры
- Далее важно узнать имя deployment-а сервиса EleWise.ELMA365.Service.Secrets, для этого воспользуемся командой которая отобразит список всех deployment-ов расположенный в пространстве имен elma365-applets
Код:
docker exec elma365 kubectl -n elma365-applets get deployments
Код:
NAME READY UP-TO-DATE AVAILABLE AGE
orgstructurebuilder-1e642ebb44d4a8f80059a56ab6ed606c 1/1 1 1 5d12h
secrets-7dcd4c4bf04b17ea37fb88e9de608c91 1/1 1 1 11h
Из всего списка следует запомнить следующее имя secrets-7dcd4c4bf04b17ea37fb88e9de608c91, т.к. этот deployment относится к сервису EleWise.ELMA365.Service.Secrets
- Таким образом, можно приступить к обновлению deployment-а сервиса EleWise.ELMA365.Service.Secrets, добавив ссылку к секрету auth-secrets, благодаря чему появится возможность использования этого секрета в сервисе. Создадим файл с обновлением patch.deployment.secrets.yaml и расположим его, например, по пути /backup/patch.deployment.secrets.yaml
Код:
spec:
template:
spec:
containers:
- name: service
volumeMounts:
- name: secrets
mountPath: /app/secrets
readOnly: true
volumes:
- name: secrets
secret:
secretName: auth-secrets
Следует учитывать, что значение тега mountPath - это директория с которой будет ассоциирован секрет auth-secrets, точнее его файл auth.secrets.json. Так же стоит помнить, что рабочая директория сервиса EleWise.ELMA365.Service.Secrets - это /app, поэтому в переменной окружения было установлено значение secrets/auth.secrets.json
- Выполняем следующую команду для обновления deployment-а с именем secrets-7dcd4c4bf04b17ea37fb88e9de608c91
Код:
docker exec elma365 kubectl -n elma365-applets patch deployment secrets-7dcd4c4bf04b17ea37fb88e9de608c91 --patch-file /backup/patch.deployment.secrets.yaml
- Итак, после того как deployment обновлен, можно воспользоваться Методом API сервиса EleWise.ELMA365.Service.Secrets для получения значений секрета auth-secrets. Воспользуемся кодом ниже, для извлечения значения имеющего путь Database:ConnectionString
Код:
async function GetValue(): Promise<void> {
try {
const response = await Namespace.services.secrets.fetch(`api/v1/secrets?path=Database:ConnectionString`);
const json = await response.json();
if (response.ok) {
const getSecretResult = json as GetSecretResult;
if (getSecretResult.success) {
// Значение полученное из Kubernates
const value = getSecretResult.value;
}
} else {
const errorResult = json as ErrorResult;
// Ошибка полученная при извлечении значения из Kubernetes
const error = errorResult.message;
}
} catch (error) {
// Ошибка полученная при извлечении значения из Kubernetes
const error = error.message;
}
}
type GetSecretResult = {
success: boolean;
value: string | undefined;
}
type ErrorResult = {
success: boolean;
message: string | undefined;
}
Если код отработает без ошибок, то получим следующее значение Secret from kubernetes!!!, которое расположено по пути Database:ConnectionString в файле auth.secrets.json секрета auth-secrets
- Таким образом можно хранить и извлекать значения секретов из Kubernetes. С исходным кодом сервиса EleWise.ELMA365.Service.Secrets можно ознакомится по этой ссылке
Полезные команды Kubernetes
Просмотр пространств имён
Используйте следующую команду, чтобы вывести список существующих пространств имён в кластере
Код:
docker exec elma365 kubectl get ns
Код:
NAME STATUS AGE
default Active 10d
elma365-applets Active 2d6h
elma365-gsvtma Active 10d
ingress-nginx Active 10d
kube-node-lease Active 10d
kube-public Active 10d
kube-system Active 10d
local-path-storage Active 10d
Просмотр секретов
Используйте следующую команду, чтобы вывести список секретов существующих в пространстве имён elma365-applets
Код:
docker exec elma365 kubectl -n elma365-applets get secrets
Код:
NAME TYPE DATA AGE
my-secret Opaque 2 30h
orgstructurebuilder-secrets Opaque 1 5h28m
regsecret kubernetes.io/dockerconfigjson 1 2d6h
yandexsecret kubernetes.io/dockerconfigjson 1 2d6h
Создание секрета
Для создания секрета воспользуемся файлом orgstructurebuilder.secrets.json со следующим содержанием
Код:
{
"Database": {
"ConnectionString": "Secret from kubernetes!!!"
}
}
Используйте следующую команду, чтобы создать секрет orgstructurebuilder-secrets в пространстве имён elma365-applets. Стоит учитывать, что ELMA365 Standart находится внутри Docker-а, поэтому путь до файла должен быть верным
Код:
docker exec elma365 kubectl -n elma365-applets create secret generic orgstructurebuilder-secrets --from-file=/backup/orgstructurebuilder.secrets.json
Просмотр секрета
Используйте следующую команду, чтобы вывести детальную информацию о секрете orgstructurebuilder-secrets в формате json из пространстве имён elma365-applets
Код:
docker exec elma365 kubectl -n elma365-applets get secrets orgstructurebuilder-secrets -o json
Код:
{
"apiVersion": "v1",
"data": {
"orgstructurebuilder.secrets.json": "ewogICAgIkRhdGFiYXNlIjogewogICAgICAgICJDb25uZWN0aW9uU3RyaW5nIjogIlNlY3JldCBmcm9tIGt1YmVybmV0ZXMhISEiCiAgICB9Cn0K"
},
"kind": "Secret",
"metadata": {
"creationTimestamp": "2024-06-21T07:48:50Z",
"name": "orgstructurebuilder-secrets",
"namespace": "elma365-applets",
"resourceVersion": "779562",
"uid": "078c25ab-2ac5-4897-b770-653a25bbac0d"
},
"type": "Opaque"
}
Используйте следующую команду, чтобы вывести содержимое поля data секрета orgstructurebuilder-secrets в формате json. Стоит учитывать, что данная команда актуальна только для случая, если секрет создавался на основе файла
Код:
docker exec elma365 kubectl -n elma365-applets get secrets orgstructurebuilder-secrets -o jsonpath='{.data.*}' | base64 -d
Код:
{
"Database": {
"ConnectionString": "Secret from kubernetes!!!"
}
}
Просмотр подов
Используйте следующую команду, чтобы вывести список подов существующих в пространстве имён elma365-applets
Код:
docker exec elma365 kubectl -n elma365-applets get pods
Код:
NAME READY STATUS RESTARTS AGE
orgstructurebuilder-1e642ebb44d4a8f80059a56ab6ed606c-68c55qfcn7 1/1 Running 1 (11h ago) 30h
Просмотр логов пода
Используйте следующую команду, чтобы вывести логи пода orgstructurebuilder-1e642ebb44d4a8f80059a56ab6ed606c-68c55qfcn7 из пространстве имён elma365-applets
Код:
docker exec elma365 kubectl -n elma365-applets logs orgstructurebuilder-1e642ebb44d4a8f80059a56ab6ed606c-68c55qfcn7
Код:
info: Microsoft.Hosting.Lifetime[14]
Now listening on: http://[::]:80
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
Hosting environment: Production
info: Microsoft.Hosting.Lifetime[0]
Content root path: /app
Просмотр развертываний
Используйте следующую команду, чтобы вывести список развертываний существующих в пространстве имён elma365-applets
Код:
docker exec elma365 kubectl -n elma365-applets get deployments
Код:
NAME READY UP-TO-DATE AVAILABLE AGE
orgstructurebuilder-1e642ebb44d4a8f80059a56ab6ed606c 1/1 1 1 31h
Обновление развертывания
Для обновления развертывания воспользуемся файлом patch.deployment.orgstructurebuilder.yaml с помощью которого добавим ссылку на секрет orgstructurebuilder-secrets
Код:
spec:
template:
spec:
containers:
- name: service
volumeMounts:
- name: secrets
mountPath: /app/secrets
readOnly: true
volumes:
- name: secrets
secret:
secretName: orgstructurebuilder-secrets
Используйте следующую команду, чтобы обновить развертывание orgstructurebuilder-1e642ebb44d4a8f80059a56ab6ed606c в пространстве имён elma365-applets. Стоит учитывать, что ELMA365 Standart находится внутри Docker-а, поэтому путь до файла должен быть верным
Код:
docker exec elma365 kubectl -n elma365-applets patch deployment orgstructurebuilder-1e642ebb44d4a8f80059a56ab6ed606c --patch-file /backup/patch.deployment.orgstructurebuilder.yaml
Просмотр развертывания
Используйте следующую команду, чтобы вывести детальную информацию о развертывании orgstructurebuilder-1e642ebb44d4a8f80059a56ab6ed606c в формате json из пространстве имён elma365-applets
Код:
docker exec elma365 kubectl -n elma365-applets get deployments orgstructurebuilder-1e642ebb44d4a8f80059a56ab6ed606c -o json
Код:
{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"annotations": {
"deployment.kubernetes.io/revision": "1"
},
"creationTimestamp": "2024-06-20T11:30:36Z",
"generation": 2,
"labels": {
"elma365.babysitter/company": "head",
"elma365.babysitter/extension-id": "c699cca8-d136-4d61-9425-7195440381e7",
"elma365.babysitter/extension-ns": "ext_c699cca8-d136-4d61-9425-7195440381e7",
"elma365.babysitter/service-code": "orgstructurebuilder",
"elma365.babysitter/service-id": "019010a1-3a2b-7eb9-8525-cc6da06ff0dc",
"elma365.babysitter/unique-name": "orgstructurebuilder-1e642ebb44d4a8f80059a56ab6ed606c",
"tier": "babysitter-manageable"
},
"name": "orgstructurebuilder-1e642ebb44d4a8f80059a56ab6ed606c",
"namespace": "elma365-applets",
"resourceVersion": "772893",
"uid": "f3b964ae-88ea-4a7e-bd8d-2997e520a4ea"
},
"spec": {
"progressDeadlineSeconds": 600,
"replicas": 1,
"revisionHistoryLimit": 10,
"selector": {
"matchLabels": {
"elma365.babysitter/unique-name": "orgstructurebuilder-1e642ebb44d4a8f80059a56ab6ed606c"
}
},
"strategy": {
"rollingUpdate": {
"maxSurge": "25%",
"maxUnavailable": "25%"
},
"type": "RollingUpdate"
},
"template": {
"metadata": {
"creationTimestamp": null,
"labels": {
"elma365.babysitter/company": "head",
"elma365.babysitter/extension-id": "c699cca8-d136-4d61-9425-7195440381e7",
"elma365.babysitter/extension-ns": "ext_c699cca8-d136-4d61-9425-7195440381e7",
"elma365.babysitter/service-code": "orgstructurebuilder",
"elma365.babysitter/service-id": "019010a1-3a2b-7eb9-8525-cc6da06ff0dc",
"elma365.babysitter/unique-name": "orgstructurebuilder-1e642ebb44d4a8f80059a56ab6ed606c",
"tier": "babysitter-manageable"
}
},
"spec": {
"containers": [
{
"env": [
{
"name": "BASE_ADDRESS",
"value": "http://192.168.19.84/"
},
{
"name": "ACCESS_TOKEN",
"value": "5da06433-b503-4b27-afca-44d96c938fee"
}
],
"image": "hubint/avtoban.elma365.orgstructurebuilder:latest",
"imagePullPolicy": "Always",
"name": "service",
"ports": [
{
"containerPort": 3005,
"protocol": "TCP"
}
],
"resources": {},
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File"
}
],
"dnsPolicy": "ClusterFirst",
"restartPolicy": "Always",
"schedulerName": "default-scheduler",
"securityContext": {},
"terminationGracePeriodSeconds": 30
}
}
},
"status": {
"availableReplicas": 1,
"conditions": [
{
"lastTransitionTime": "2024-06-20T11:30:38Z",
"lastUpdateTime": "2024-06-20T11:30:38Z",
"message": "Deployment has minimum availability.",
"reason": "MinimumReplicasAvailable",
"status": "True",
"type": "Available"
},
{
"lastTransitionTime": "2024-06-20T11:30:36Z",
"lastUpdateTime": "2024-06-20T11:30:38Z",
"message": "ReplicaSet \"orgstructurebuilder-1e642ebb44d4a8f80059a56ab6ed606c-68c55446b8\" has successfully progressed.",
"reason": "NewReplicaSetAvailable",
"status": "True",
"type": "Progressing"
}
],
"observedGeneration": 2,
"readyReplicas": 1,
"replicas": 1,
"updatedReplicas": 1
}
}