Skip to content

فصل ۱۴ — کنترل دسترسی مبتنی بر نقش (RBAC)

در این نقطه، تقریباً هر cluster Kubernetes که می‌بینید role-based access control (RBAC) فعال دارد. پس احتمالاً حداقل تا حدی با RBAC برخورد داشته‌اید. شاید اول نتوانستید به cluster دسترسی داشته باشید تا با یک incantation جادویی RoleBinding اضافه کردید و user را به role map کردید. اما حتی با exposure قبلی، ممکن است تجربه زیادی در فهم RBAC در Kubernetes، کاربرد آن و استفاده موفق از آن نداشته باشید.

موضوع این فصل همین است.

RBAC با نسخه ۱.۵ به Kubernetes معرفی شد و در Kubernetes 1.8 generally available شد. Role-based access control مکانیزمی برای محدود کردن هم دسترسی و هم action روی Kubernetes API فراهم می‌کند تا فقط userهای مناسب به API در cluster دسترسی داشته باشند. RBAC component حیاتی هم برای سخت‌تر کردن دسترسی به cluster Kubernetes که application را deploy می‌کنید و (احتمالاً مهم‌تر) جلوگیری از accidentهای غیرمنتظره‌ای است که یک نفر در namespace اشتباه فکر می‌کند test cluster را destroy می‌کند در حالی که production را down می‌کند.

امنیت multitenant در Kubernetes موضوعی پیچیده و چندوجهی است که volume خودش را می‌طلبد. اگرچه RBAC در محدود کردن دسترسی به Kubernetes API مفید است، مهم است به یاد داشته باشید هر کسی که بتواند arbitrary code داخل cluster Kubernetes اجرا کند، عملاً root privilege روی کل cluster به دست می‌آورد. approachهایی هست که این حملات را سخت‌تر و پرهزینه‌تر می‌کند و setup درست RBAC بخشی از این دفاع است. اما اگر روی امنیت multitenant hostile تمرکز دارید، باور نکنید RBAC به‌تنهایی کافی است. باید Podهای running در cluster را isolate کنید تا امنیت multitenant مؤثر فراهم شود. معمولاً با hypervisor isolated container، یا نوعی container sandbox، یا هر دو انجام می‌شود.

قبل از جزئیات RBAC در Kubernetes، درک high-level از RBAC به‌عنوان concept، و authentication و authorization به‌طور کلی‌تر مفید است.

هر request به Kubernetes اول authenticate می‌شود. Authentication هویت caller صادرکننده request را فراهم می‌کند. می‌تواند به سادگی بگوید request unauthenticated است، یا عمیقاً با authentication provider قابل plug (مثلاً Azure Active Directory) integrate شود تا identity در آن سیستم third-party establish شود.

جالب است Kubernetes identity store built-in ندارد و به‌جای آن روی integrate کردن منابع identity دیگر در خود تمرکز می‌کند.

وقتی userها properly identify شدند، فاز authorization تعیین می‌کند آیا مجاز به انجام request هستند. Authorization ترکیبی از identity user، resource (عملاً HTTP path) و verb یا actionی است که user می‌خواهد انجام دهد. اگر user مشخص برای انجام آن action روی آن resource مجاز باشد، request ادامه می‌یابد. در غیر این صورت HTTP 403 error برمی‌گردد. جزئیات بیشتر این فرایند در بخش‌های بعد آمده.

Role-Based Access Control

برای مدیریت درست دسترسی در Kubernetes، درک نحوه تعامل identity، role و role binding برای کنترل «چه کسی چه کاری روی چه resourceای می‌تواند انجام دهد» حیاتی است. در ابتدا RBAC چالش فهم به نظر می‌رسد، با seriesی از conceptهای abstract به‌هم‌پیوندخورده؛ اما وقتی فهمیدید، مدیریت دسترسی cluster straightforward و safe است.

Identity در Kubernetes

هر request که به Kubernetes می‌آید با identityای مرتبط است. حتی request بدون identity به group system:unauthenticated مرتبط است.

Kubernetes بین user identity و service account identity تمایز قائل می‌شود. Service accountها توسط خود Kubernetes ساخته و مدیریت می‌شوند و عموماً با componentهای running داخل cluster مرتبط‌اند. User accountها همه accountهای دیگر مرتبط با user واقعی cluster هستند و اغلب automation مثل continuous delivery as a service که خارج cluster اجرا می‌شود را هم شامل می‌شوند.

Kubernetes از interface generic برای authentication provider استفاده می‌کند. هر provider یک username و optionally مجموعه groupهایی که user به آن‌ها تعلق دارد تأمین می‌کند. Kubernetes تعداد authentication provider مختلف پشتیبانی می‌کند، از جمله:

  • HTTP Basic Authentication (largely deprecated)
  • x509 client certificate
  • Static token file روی host
  • Cloud authentication provider مثل Azure Active Directory و AWS Identity and Access Management (IAM)
  • Authentication webhook

اگرچه بیشتر نصب‌های managed Kubernetes authentication را برایتان configure می‌کنند، اگر authentication خودتان deploy می‌کنید باید flagهای مناسب روی Kubernetes API server configure کنید.

درک Roleها و Role Bindingها

Identity فقط آغاز authorization در Kubernetes است. وقتی سیستم identity request را می‌داند، باید تعیین کند request برای آن user مجاز است. برای این کار از concept کلی role و role binding استفاده می‌کند.

Role مجموعه‌ای از capabilityهای abstract است. مثلاً role appdev ممکن است ability ایجاد Pod و service را نشان دهد. Role binding انتساب role به یک یا چند identity است. پس binding role appdev به user identity alice نشان می‌دهد Alice ability ایجاد Pod و service را دارد.

Roleها و Role Bindingها در Kubernetes

در Kubernetes دو جفت resource مرتبط role و role binding را نشان می‌دهند. یک جفت فقط روی namespace اعمال می‌شود (Role و RoleBinding) و جفت دیگر در کل cluster (ClusterRole و ClusterRoleBinding).

اول Role و RoleBinding را بررسی کنیم. resource Role namespaced است و capability در همان namespace را نشان می‌دهد. نمی‌توانید roleهای namespaced را برای resourceهای non-namespaced (مثلاً CustomResourceDefinition) استفاده کنید، و binding RoleBinding به role فقط authorization در namespace Kubernetes که هم Role و هم RoleDefinition در آن هست فراهم می‌کند.

به‌عنوان مثال concrete، role ساده‌ای که به identity ability ایجاد و modify کردن Pod و service می‌دهد:

yaml
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  namespace: default
  name: pod-and-services
rules:
- apiGroups: [""]
  resources: ["pods", "services"]
  verbs: ["create", "delete", "get", "list", "patch", "update", "watch"]

برای bind کردن این Role به user alice، RoleBindingی لازم است که شبیه زیر است. این role binding هم group mydevs را به همان role bind می‌کند:

yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  namespace: default
  name: pods-and-services
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: User
  name: alice
- apiGroup: rbac.authorization.k8s.io
  kind: Group
  name: mydevs
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: pod-and-services

گاهی role می‌خواهید که روی کل cluster اعمال شود، یا دسترسی به resourceهای cluster-level را محدود کنید. برای این کار از resourceهای ClusterRole و ClusterRoleBinding استفاده می‌کنید. تا حد زیادی مشابه peerهای namespaced هستند، اما scope بزرگ‌تر دارند.

Verbها برای Kubernetes role

Roleها هم از resource (مثلاً «Pods») و هم verb که action قابل انجام روی آن resource را توصیف می‌کند تعریف می‌شوند. Verbها تقریباً با HTTP methodها مطابقت دارند. verbهای رایج در Kubernetes RBAC در جدول ۱۴-۱ فهرست شده‌اند.

VerbHTTP methodتوضیح
createPOSTresource جدید بسازد.
deleteDELETEresource موجود را حذف کند.
getGETیک resource بگیرد.
listGETمجموعه resourceها را list کند.
patchPATCHresource موجود را با تغییر partial modify کند.
updatePUTresource موجود را با object کامل modify کند.
watchGETبرای streaming update به resource watch کند.
proxyGETاز طریق streaming WebSocket proxy به resource وصل شود.

استفاده از built-in role

البته طراحی role خودتان می‌تواند complicated و time-consuming باشد. علاوه بر این، Kubernetes تعداد زیادی system identity شناخته‌شده (مثلاً scheduler) دارد که مجموعه capability مشخص می‌خواهند. در نتیجه Kubernetes تعداد زیادی built-in cluster role دارد. با اجرای زیر می‌بینید:

$ kubectl get clusterroles

بیشتر این built-in roleها برای system utility هستند، اما چهار تا برای end user عمومی طراحی شده‌اند:

  • Role cluster-admin دسترسی کامل به کل cluster می‌دهد.
  • Role admin دسترسی کامل به یک namespace کامل می‌دهد.
  • Role edit به end user اجازه modify کردن چیزها در namespace می‌دهد.
  • Role view دسترسی read-only به namespace می‌دهد.

بیشتر clusterها از قبل ClusterRole binding زیادی setup شده دارند؛ با kubectl get clusterrolebindings می‌بینید.

Auto-reconciliation built-in role

وقتی Kubernetes API server start می‌شود، خودکار تعدادی default ClusterRole که در code API server تعریف شده install می‌کند. یعنی اگر built-in cluster role را modify کنید، modificationها transient هستند. هر بار API server restart شود (مثلاً برای upgrade) تغییرات overwrite می‌شوند.

برای جلوگیری، قبل از هر modification دیگر باید annotation rbac.authorization.kubernetes.io/autoupdate با value false به resource built-in ClusterRole اضافه کنید. اگر این annotation روی false باشد، API server resource modified ClusterRole را overwrite نمی‌کند.

به‌طور پیش‌فرض، Kubernetes API server cluster roleی install می‌کند که به userهای system:unauthenticated دسترسی به API discovery endpoint API server می‌دهد. برای cluster exposed به environment hostile (مثلاً public internet) این ایده بد است و حداقل یک vulnerability امنیتی جدی از این exposure بوده. در نتیجه اگر Kubernetes service را روی public internet یا environment hostile دیگر run می‌کنید، مطمئن شوید flag --anonymous-auth=false روی API server تنظیم شده.

تکنیک‌های مدیریت RBAC

مدیریت RBAC برای cluster می‌تواند complicated و frustrating باشد. نگران‌کننده‌تر این است که RBAC misconfigured می‌تواند به issue امنیتی منجر شود. خوشبختانه چند tool و technique مدیریت RBAC را آسان‌تر می‌کند.

تست Authorization با can-i

اولین tool مفید دستور auth can-i برای kubectl است. برای تست اینکه user مشخص action مشخصی می‌تواند انجام دهد بسیار مفید است. می‌توانید can-i را برای validate کردن settingهای پیکربندی هنگام configure کردن cluster استفاده کنید، یا از user بخواهید هنگام filing error یا bug report دسترسیش را validate کند.

در ساده‌ترین usage، can-i یک verb و resource می‌گیرد.

مثلاً این دستور نشان می‌دهد آیا user فعلی kubectl مجاز به create کردن Pod است:

$ kubectl auth can-i create pods

subresource مثل log یا port forwarding را هم با flag --subresource تست کنید:

$ kubectl auth can-i get pods --subresource=logs

مدیریت RBAC در Source Control

مثل همه resource در Kubernetes، resourceهای RBAC با JSON یا YAML model شده‌اند. با این representation متنی منطقی است این resourceها را در version control نگه دارید. نیاز قوی audit، accountability و rollback برای تغییر policy RBAC یعنی version control برای resourceهای RBAC ضروری است.

خوشبختانه ابزار خط فرمان kubectl دستور reconcile دارد که تا حدی شبیه kubectl apply عمل می‌کند و مجموعه متنی role و role binding را با state فعلی cluster reconcile می‌کند.

می‌توانید اجرا کنید:

$ kubectl auth reconcile -f some-rbac-config.yaml

و data در فایل با cluster reconcile می‌شود. اگر قبل از اعمال تغییرات ببینید، flag --dry-run اضافه کنید تا print کند اما submit نکند.

موضوعات پیشرفته

وقتی به basics role-based access control orient شدید، مدیریت دسترسی cluster نسبتاً آسان است؛ اما هنگام مدیریت تعداد زیاد user یا role، capabilityهای advanced اضافی برای مدیریت RBAC در scale وجود دارد.

Aggregating ClusterRole

گاهی role می‌خواهید که ترکیبی از roleهای دیگر باشد. یک گزینه clone کردن همه rule از یک ClusterRole به ClusterRole دیگر است، اما complicated و error-prone است چون تغییر یک ClusterRole خودکار در دیگری reflect نمی‌شود. به‌جای آن Kubernetes RBAC از aggregation rule برای combine کردن چند role در role جدید پشتیبانی می‌کند. role جدید همه capability همه aggregate roleها را combine می‌کند و هر تغییر در هر subrole constituent خودکار به aggregate role propagate می‌شود.

مثل همه aggregation یا grouping در Kubernetes، ClusterRoleهای aggregate با label selector مشخص می‌شوند. در این case خاص، فیلد aggregationRule در resource ClusterRole فیلد clusterRoleSelector دارد که label selector است. همه resource ClusterRole که این selector match کند dynamically در array rules در resource aggregate ClusterRole aggregate می‌شوند.

best practice مدیریت resource ClusterRole ساخت تعدادی cluster role fine-grained و سپس aggregate کردن آن‌ها برای cluster role سطح بالاتر یا broadly defined است. built-in cluster roleها این‌طور تعریف شده‌اند. مثلاً built-in role edit شبیه این است:

yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: edit
  ...
aggregationRule:
  clusterRoleSelectors:
  - matchLabels:
      rbac.authorization.k8s.io/aggregate-to-edit: "true"
...

یعنی role edit aggregate همه object ClusterRole است که label rbac.authorization.k8s.io/aggregate-to-edit روی "true" دارند.

استفاده از Group برای Binding

وقتی تعداد زیادی نفر در organizationهای مختلف با دسترسی مشابه به cluster مدیریت می‌کنید، generally best practice استفاده از group برای مدیریت roleهایی است که دسترسی cluster را define می‌کنند، به‌جای اضافه کردن individually binding به identity مشخص. وقتی group را به ClusterRole یا namespace Role bind می‌کنید، هر کسی member آن group باشد به resource و verb تعریف‌شده توسط آن role دسترسی می‌گیرد. پس برای enable کردن دسترسی فرد به role group، آن فرد باید به group اضافه شود.

چند دلیل استفاده از group برای مدیریت دسترسی در scale preferred strategy است. اول، در organization بزرگ دسترسی cluster بر اساس teamی که فرد part of آن است define می‌شود نه identity مشخص. مثلاً کسی part of frontend operations team به view و edit resourceهای frontend نیاز دارد، در حالی که شاید فقط view/read access به resource backend لازم باشد. grant کردن privilege به group ارتباط team و capability را clear می‌کند. وقتی role به individual grant می‌شود، فهم privilege مناسب (یعنی minimal) برای هر team سخت‌تر است، به‌ویژه وقتی فرد part of چند team مختلف باشد.

مزایای اضافی binding role به group به‌جای individual سادگی و consistency است. وقتی کسی join یا leave team می‌کند، straightforward است فقط add یا remove از group در یک operation. اگر به‌جای آن bindingهای role مختلف identity را remove کنید، ممکن است binding کم یا زیاد remove شود و دسترسی غیرضروری یا جلوگیری از action لازم رخ دهد. علاوه بر این چون فقط یک set group role binding برای maintain وجود دارد، کار زیادی برای اطمینان از permission یکسان و consistent همه member team لازم نیست.

علاوه بر این، many group system «just in time» (JIT) access enable می‌کنند که people فقط موقتاً به group در پاسخ event (مثلاً page نیمه‌شب) اضافه شوند نه standing access. یعنی audit کنید چه کسی در زمان مشخص دسترسی داشته و ensure کنید حتی identity compromised به‌طور کلی به production infrastructure دسترسی نداشته باشد.

در نهایت در many case همین groupها برای مدیریت دسترسی resource دیگر از facility تا document و machine login استفاده می‌شوند. پس استفاده از همان group برای access control Kubernetes مدیریت را dramatically ساده می‌کند.

برای bind کردن group به ClusterRole از kind Group برای subject در binding استفاده کنید:

yaml
...
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: Group
  name: my-great-groups-name
...

در Kubernetes groupها توسط authentication provider تأمین می‌شوند. notion قوی group داخل Kubernetes نیست؛ فقط اینکه identity می‌تواند part of یک یا چند group باشد و آن groupها via binding با Role یا ClusterRole مرتبط شوند.

خلاصه

وقتی با cluster کوچک و team کوچک شروع می‌کنید، کافی است هر member team دسترسی equivalent به cluster داشته باشد. اما با رشد team و mission critical شدن product، محدود کردن دسترسی به بخش‌های cluster crucial است. در cluster well-designed، دسترسی به minimal set people و capability لازم برای manage کردن efficient application در cluster محدود است. فهم نحوه implement RBAC در Kubernetes و استفاده از آن capabilityها برای کنترل دسترسی cluster برای developer و cluster administrator مهم است. مثل build out testing infrastructure، best practice setup درست RBAC زودتر است نه دیرتر. شروع با foundation درست far easier از retrofit بعداً است. امیدواریم اطلاعات این فصل grounding لازم برای اضافه کردن RBAC به cluster را داده باشد.