Вы когда-нибудь пытались получить программный доступ к Jaeger в OpenShift? Это может быть немного сложно. Иногда это необходимо, потому что вы хотите, например, получить доступ к REST API, который не документирован, потому что предназначен для внутреннего использования. Или вы хотите (как в моем случае) протестировать что-то из пользовательского интерфейса.
Перед прочтением этой статьи
Эта статья о том, как получить доступ к службе запросов Jaeger при использовании стратегии развертывания «production» и развертывании через Jaeger Operator. Некоторые шаги могут быть такими же, если вы используете другие методы развертывания. Даже если вы отключили безопасность, эти шаги могут быть не нужны:
apiVersion: jaegertracing.io/v1
kind: Jaeger
metadata:
name: disable-oauth-proxy
spec:
ingress:
security: none
Кроме того, учтите, что это описание для OpenShift. Поэтому, если вы используете Kubernetes без прокси безопасности или чего-то подобного, вам не нужно будет выполнять эти шаги для доступа к конечным точкам запросов Jaeger. Или (если вы используете другой прокси) вам нужно будет настроить свои учетные данные для доступа к API. Я буду считать, что вы используете OpenShift Oauth Proxy.
Получение доступа к службе запросов Jaeger
Представим, что я развернул следующий CRD (kubectl create -f simple-prod.yaml
) в пространстве имен israel
:
apiVersion: jaegertracing.io/v1
kind: Jaeger
metadata:
name: simple-prod
spec:
strategy: production
storage:
type: elasticsearch
elasticsearch:
nodeCount: 1
resources:
requests:
cpu: 200m
memory: 1Gi
limits:
memory: 1Gi
Результатом выполнения curl
против созданного маршрута OpenShift будет ошибка 403:
$ curl https://$(kubectl get route simple-prod -o jsonpath='{.spec.host}') -I
HTTP/1.1 403 Forbidden
Set-Cookie: _oauth_proxy=; Path=/; Domain=simple-prod-israel.apps.mycluster.iblancasa.com; Expires=Thu, 05 May 2022 11:09:34 GMT; HttpOnly; Secure; SameSite
Date: Thu, 05 May 2022 12:09:34 GMT
Content-Type: text/html; charset=utf-8
Set-Cookie: 3f978cf9c2d3ee8d70cad1d11aef9dcd=8d2f11be8db90157d1e73d19b515f187; path=/; HttpOnly; Secure; SameSite=None
Если вы не указали опцию -I
для получения только заголовков, вы получите полный HTML-код с веб-страницы регистрации. Давайте посмотрим, как получить «правильный» ответ от сервера.
Первым шагом будет создание учетной записи службы. Из документации OpenShift:
Сервисный аккаунт — это аккаунт OpenShift Container Platform, который позволяет компоненту напрямую обращаться к API.
Я назову свой сервисный аккаунт «automation-access». Итак, мой файл sa.yaml
содержит:
apiVersion: v1
kind: ServiceAccount
metadata:
name: automation-access
И создадим его в OpenShift с помощью kubectl create -f sa.yaml
:
$ kubectl create -f sa.yaml
serviceaccount/automation-access created
Теперь нам нужно создать Cluster Role Binding. Из документации Kubernetes:
Привязка роли предоставляет права, определенные в роли, пользователю или набору пользователей. Она содержит список субъектов (пользователей, групп или учетных записей служб) и ссылку на предоставляемую роль. RoleBinding предоставляет разрешения в пределах определенного пространства имен, в то время как ClusterRoleBinding предоставляет такой доступ в масштабах всего кластера.
В качестве упрощения мы можем использовать привязки ролей кластера для установления отношений между, например, учетной записью службы и ролью кластера. В нашем случае будет достаточно system:auth-delegator для учетной записи службы jaeger-operator
из пространства имен observability
и cluster-reader для учетной записи службы, которую мы создали ранее. Наш файл crb.yaml
будет похож на этот:
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: jaeger-operator-with-auth-delegator
namespace: observability
subjects:
- kind: ServiceAccount
name: jaeger-operator
namespace: observability
roleRef:
kind: ClusterRole
name: system:auth-delegator
apiGroup: rbac.authorization.k8s.io
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: automation-access-bind
subjects:
- kind: ServiceAccount
name: automation-access
namespace: israel
roleRef:
kind: ClusterRole
name: cluster-reader
apiGroup: rbac.authorization.k8s.io
И применим его к нашему кластеру OpenShift, используя: kubectl create -f crb.yaml
:
$ kubectl create -f crb.yaml
clusterrolebinding.rbac.authorization.k8s.io/jaeger-operator-with-auth-delegator created
clusterrolebinding.rbac.authorization.k8s.io/automation-access-bind created
Наконец, нам нужно установить некоторые дополнительные опции для нашего развертывания Jaeger (jaeger-sar.yaml
):
apiVersion: jaegertracing.io/v1
kind: Jaeger
metadata:
name: simple-prod
spec:
query:
options:
query.bearer-token-propagation: true
ingress:
openshift:
sar: '{"namespace": "israel", "resource": "pods", "verb": "get"}'
delegateUrls: '{"/":{"namespace": "israel", "resource": "pods", "verb": "get"}}'
options:
pass-access-token: true
pass-user-bearer-token: true
scope: "user:info user:check-access"
pass-basic-auth: false
Затем мы применим его с помощью kubectl apply -f jaeger-sa.yaml
:
$ kubectl apply -f jaeger-sar.yaml
Warning: resource jaegers/simple-prod is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by kubectl apply. kubectl apply should only be used on resources created declaratively by either kubectl create --save-config or kubectl apply. The missing annotation will be patched automatically.
jaeger.jaegertracing.io/simple-prod configured
Хорошо! Мы почти у цели. Следующим шагом будет получение маркера, который позволит нам получить программный доступ к службе запросов Jaeger. Чтобы получить токен, нам нужно узнать имя используемого секрета Kubernetes. Мы можем получить эту информацию с помощью следующей команды:
$ kubectl get sa automation-access -o jsonpath='{.secrets}'
[{"name":"automation-access-token-q2p2x"},{"name":"automation-access-dockercfg-xvzsq"}]
В результате мы получим имена двух секретов. Мы будем использовать тот, который называется auomation-access-token-<ID>
. Если вы используете yq, команда может быть такой:
$ kubectl get sa automation-access -o yaml | yq eval '.secrets[] | select( .name == "*-token-*")'.name
automation-access-token-q2p2x
И, наконец, мы извлекаем токен из секрета:
$ kubectl get secret automation-access-token-q2p2x -o jsonpath='{.data.token}' | base64 -d
eyJhbGciOiJSUzI1NiIsImtpZCI6Iks3TXcwUWhyb3BVdUVJblhkQmVQT25Fek1KVVlfa2RPV3dDZWpJVXpmekUifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJpc3JhZWwiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlY3JldC5uYW1lIjoiYXV0b21hdGlvbi1hY2Nlc3MtdG9rZW4tcTJwMngiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiYXV0b21hdGlvbi1hY2Nlc3MiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiI1NGY1ZDE0MC1lMDEwLTQ5NWYtYWE4Yy0wNmQ3ZjIwNjg3OGIiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6aXNyYWVsOmF1dG9tYXRpb24tYWNjZXNzIn0.J5USv-olD1vU0A5tL8TT1SDoH-jf5f58hSIEPnkkiZzTiOjHHx2Vj2v1p0bm26epfTQwLV3TfIsgcsV7tnpC0cR64MmDQe9EuBtNonJqV45nTkSoboWuBfeSxXqjk7Tuj_bcZcutcA0vsVHzAglb-Z0wavx9ETfQJueDWTzF6Cry5HxVxYn6ytogHfbaEgiLN9HNeZBWW4xi7JAzY-2viECrFq1yEIJKzWDihZScFkyX2fu1UDpFLH2ewA8N6bdqSd5FTEna0JS0e8yxQcGo-oXykDW2G_YcLDBSrCpQaji390FgMp_6dEl1yHSazGgCaKwulwOU4Rr6usf807mdBQ
Эта команда получает токен из секрета и декодирует его. Нам нужно указать этот токен в заголовке Authorization
при выполнении вызова curl
:
$ export TOKEN=$(kubectl get secret automation-access-token-q2p2x -o jsonpath='{.data.token}' | base64 -d)
$ curl https://$(kubectl get route simple-prod -o jsonpath='{.spec.host}') -I -H "Authorization: Bearer $TOKEN"
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Date: Thu, 05 May 2022 12:44:06 GMT
Gap-Auth: system:serviceaccount:israel:automation-sa@cluster.local
Gap-Upstream-Address: localhost:16686
Vary: Accept-Encoding
Set-Cookie: 3f978cf9c2d3ee8d70cad1d11aef9dcd=2e6b6fcf2050268c74e1aabcf71e9bab; path=/; HttpOnly; Secure; SameSite=None
Cache-control: private
Спасибо за прочтение! Надеюсь, эта статья помогла вам! 🙂