Istio security pillar предоставляет комплексное решение для защиты рабочих нагрузок с помощью надежной идентификации (с дополнительной интеграцией с SPIRE с версии 1.14), аутентификации и авторизации (с дополнительной интеграцией с OPA). Istio sidecar (сервисный прокси) и ingressgateway (пограничный прокси) служат в качестве PEP для всего mesh.
Согласно NIST SP 800-207, ни один ресурс не является доверенным по своей сути, 1) каждый актив (сервис) ДОЛЖЕН иметь оценку своей безопасности через PEP перед тем, как запрос будет удовлетворен … 2) и оценка должна быть непрерывной в течение всего времени, пока длится сессия. Istio обычно работает на уровне L7. И для реализации стратегии Defense-in-Depth нам также необходимо дополнить ее принудительным применением L3/4 через NetworkPolicy. Пожалуйста, ознакомьтесь с дополнительными соображениями безопасности, а мы не будем об этом говорить. Вместо этого позвольте мне рассказать вам о том, как защитить рабочую нагрузку с помощью Istio с JWT.
Вы можете получить бесплатный JWT-токен через auth0. Мы будем использовать его для демонстрации.
Очевидно, что нам нужно обеспечить mTLS с помощью PeerAuthentication. По умолчанию для Istio enableAutoMtls
установлено значение true
, но он был в режиме PERMISSIVE
.
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: default
namespace: istio-system
spec:
mtls:
mode: STRICT
Нам нужно убедиться, что запрос ДОЛЖЕН быть отклонен на границе (istio-ingressgateway) либо без JWT-токена, либо с недействительным JWT-токеном с помощью комбинации RequestAuthentication
и AuthorizationPolicy
.
RequesetAuthentication
CRD убедится, что JWT-токен соответствует заданным jwtRules
.
apiVersion: security.istio.io/v1beta1
kind: RequestAuthentication
metadata:
name: jwt-authn-gw
namespace: istio-gateway
spec:
selector:
matchLabels:
istio: ingressgateway
jwtRules:
- issuer: "https://dev-wl5b26zy.us.auth0.com/"
jwksUri: "https://dev-wl5b26zy.us.auth0.com/.well-known/jwks.json"
audiences:
- "https://httpbin/api"
forwardOriginalToken: true
Токен JWT обычно использует RS256 (RSA Signature with SHA-256) в качестве алгоритма асимметричной подписи. Istio убедится, что токен действительно действителен и защищен от взлома, проверив цифровую подпись через jwksUri
. Когда приходит запрос, он проходит через различные HTTP фильтры, и один из них — envoy.filters.http.jwt_authn
. Для большей эффективности JWKS будет «кэшироваться» в localJwks
для улучшения производительности вместо того, чтобы каждый раз обращаться к конечной точке jwksUri
.
...
{
"name": "envoy.filters.http.jwt_authn",
"typedConfig": {
"@type": "type.googleapis.com/envoy.extensions.filters.http.jwt_authn.v3.JwtAuthentication",
"providers": {
"origins-0": {
"issuer": "https://dev-wl5b26zy.us.auth0.com/",
"audiences": [
"https://httpbin/api"
],
"localJwks": {
"inlineString": "..."
},
"forward": true,
"payloadInMetadata": "https://dev-wl5b26zy.us.auth0.com/"
}
},
...
}
...
Фильтр istio_authn
находится сразу после фильтра jwt_authn
. И он также пытается проверить эмитента:
{
"name": "istio_authn",
"typedConfig": {
"@type": "type.googleapis.com/istio.envoy.config.filter.http.authn.v2alpha1.FilterConfig",
"policy": {
"origins": [
{
"jwt": {
"issuer": "https://dev-wl5b26zy.us.auth0.com/"
}
}
],
"originIsOptional": true,
"principalBinding": "USE_ORIGIN"
},
"skipValidateTrustDomain": true
}
}
Просто RequesetAuthentication
будет недостаточно, поскольку запрос без каких-либо учетных данных аутентификации будет принят, но не будет иметь аутентифицированной личности. Вот почему крайне важно иметь AuthorizationPolicy
для обеспечения соблюдения.
Во-первых, она предусматривает, что запрос будет отклонен на istio-ingressgateway, если у него нет RequestPrincipal
.
apiVersion: "security.istio.io/v1beta1"
kind: AuthorizationPolicy
metadata:
name: deny-jwt-gw
namespace: istio-gateway
spec:
selector:
matchLabels:
istio: ingressgateway
action: DENY
rules:
- from:
- source:
notRequestPrincipals: ["*"]
Во-вторых, на уровне сервиса он должен удовлетворять требованиям, которые ожидает рабочая нагрузка. Для того чтобы это работало, важно иметь forwardOriginalToken: true
, чтобы разрешить пересылку JWT-токена от istio-ingressgateway к рабочей нагрузке.
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: require-jwt-httpbin
namespace: default
spec:
selector:
matchLabels:
app: httpbin
action: ALLOW
rules:
- from:
- source:
requestPrincipals: ["https://dev-wl5b26zy.us.auth0.com//8qPXVf5npNa4yXmeyHhnGh5GDgrDK3B5@clients"]
when:
- key: request.auth.claims[scope]
values: ["read:messages"]
- key: request.auth.claims[aud]
values: ["https://httpbin/api"]
Эти правила были «закодированы» в боковом EnvoyProxy HTTP Filter рабочей нагрузки под названием envoy.filters.http.rbac
. Любое нарушение приведет к 403 Forbidden
с ошибкой RBAC: access denied
.
{
"name": "envoy.filters.http.rbac",
"typedConfig": {
"@type": "type.googleapis.com/envoy.extensions.filters.http.rbac.v3.RBAC",
"rules": {
"policies": {
"ns[default]-policy[require-jwt-httpbin]-rule[0]": {
"permissions": [
{
"andRules": {
"rules": [
{
"any": true
}
]
}
}
],
"principals": [
{
"andIds": {
"ids": [
{
"orIds": {
"ids": [
{
"metadata": {
"filter": "istio_authn",
"path": [
{
"key": "request.auth.principal"
}
],
"value": {
"stringMatch": {
"exact": "https://dev-wl5b26zy.us.auth0.com//8qPXVf5npNa4yXmeyHhnGh5GDgrDK3B5@clients"
}
}
}
}
]
}
},
...
},
"shadowRulesStatPrefix": "istio_dry_run_allow_"
}
}
Спасибо, что читаете и учитесь вместе со мной. Если вы хотите запустить его самостоятельно, вот исходный код и инструкции.
Вуаля!