مزایای اصلی supplemental groups در GA Kubernetes
در این بخش به توضیح دقیق مفهوم supplemental groups و نحوهٔ پیکربندی آن در Pod و تأثیر آن روی امنیت میپردازیم.
خبر خوب برای تیمهای DevOps/SRE: در Kubernetes نسخه 1.35، کنترل ریزدانه روی supplemental groups به حالت عمومی (GA) ارتقاء پیدا کرده است و فیلد جدید Pod با نام supplementalGroupsPolicy اکنون بهطور کامل در دسترس است 🙂.
این قابلیت اجازه میدهد تا به صورت دقیقتری مشخص کنید چه گروههای تکمیلی (supplemental groups) برای پروسسهای کانتینری در یک Pod تعیین شوند. هدف اصلی افزایش امنیت، بهخصوص هنگام دسترسی به حجمها (volumes)، و شفافتر کردن UID/GID داخل کانتینرها است تا مانیتورینگ و ارزیابی امنیتی آسانتر شود.
اگر کلاستر خود را از نسخههای قدیمیتر (مثلاً 1.32 یا قبلتر) ارتقا میدهید، توجه داشته باشید که از زمان عرضهٔ بتا (v1.33) برخی رفتارها تغییر کردهاند؛ حتماً release notes و ملاحظات ارتقاء را بررسی کنید تا از تأثیرات احتمالی روی بارهای کاری خود آگاه شوید 🔎.
دلیل این تغییر چیست؟ به طور پیشفرض عضویت گروه برای کاربر اصلی کانتینر از محتوای /etc/group داخل image خوانده و با اطلاعات Pod ادغام میشود. این رفتار از پیادهسازیهای قدیمی CRI (مثل Docker) به ارث رسیده و تا کنون به طور گسترده بازنگری نشده بود.
نمونهٔ سادهای از مانیفست Pod که مقادیر runAsUser، runAsGroup و supplementalGroups را مشخص میکند:
apiVersion: v1
kind: Pod
metadata:
name: implicit-groups-example
spec:
securityContext:
runAsUser: 1000
runAsGroup: 3000
supplementalGroups: [4000]
containers:
- name: example-container
image: registry.k8s.io/e2e-test-images/agnhost:2.45
securityContext:
allowPrivilegeEscalation: false
با اجرای دستور id داخل کانتینر انتظار میرود خروجی چیزی شبیه به این باشد:
uid=1000 gid=3000 groups=3000,4000,50000
حالا ممکن است بپرسید این GIDِ 50000 از کجا آمده، در حالی که در مانیفست Pod تعریف نشده؟ پاسخ در محتویات /etc/group داخل image است:
user-defined-in-image:x:1000: group-defined-in-image:x:50000:user-defined-in-image
به عبارت دیگر، عضویت گروهی که در /etc/group تصویر تعریف شده برای کاربر اصلی کانتینر بهطور ضمنی با اطلاعات Pod ترکیب میشود. این ترکیب ضمنی میتواند ریسک امنیتی ایجاد کند، چون آن GIDها در مانیفست Pod وجود ندارند و بنابراین ابزارهای سیاستگذاری یا بررسی دسترسی ممکن است آنها را نادیده بگیرند — که میتواند منجر به دسترسی غیرمنتظره به فایلها و حجمها شود.
برای حل این مشکل، فیلد supplementalGroupsPolicy معرفی شد که مشخص میکند supplemental groups چگونه محاسبه شوند. دو سیاست اصلی عبارتاند از:
– Merge: گروههای تعریفشده در /etc/group برای کاربر اصلی کانتینر ادغام میشوند. این رفتار پیشفرض برای سازگاری به عقب است.
– Strict: فقط GIDهایی که صراحتاً در fsGroup، supplementalGroups یا runAsGroup مشخص شدهاند به عنوان گروههای تکمیلی به پروسسها اضافه میشوند؛ عضویتهای تعریفشده در /etc/group نادیده گرفته میشوند.
نمونهٔ مانیفست با supplementalGroupsPolicy: Strict:
apiVersion: v1
kind: Pod
metadata:
name: strict-supplementalgroups-policy-example
spec:
securityContext:
runAsUser: 1000
runAsGroup: 3000
supplementalGroupsPolicy: Strict
supplementalGroups: [4000]
containers:
- name: example-container
image: registry.k8s.io/e2e-test-images/agnhost:2.45
command: ["sh", "-c", "sleep 1h"]
securityContext:
allowPrivilegeEscalation: false
خروجی دستور id در این حالت باید چیزی شبیه زیر باشد (یعنی GID های ضمنی حذف شدهاند):
uid=1000 gid=3000 groups=3000,4000
نکتهٔ مهم: اگر کانتینر امتیازات کافی داشته باشد، پروسس میتواند هویت خود را با فراخوانیهایی مثل setuid(2) یا setgroups(2) تغییر دهد؛ بنابراین supplementalGroupsPolicy تنها هویتِ اولیهٔ فرآیند را کنترل میکند. برای کاهش این خطر، پیشنهادات ساده و موثر:
– تنظیم securityContext: privileged: false و allowPrivilegeEscalation: false در کانتینر یا استفاده از خطمشیهای محدودتر در سطح Pod Security Standards.
– حذف مجوزهای غیرضروری و هماهنگی با استانداردهای سختگیرانهٔ امنیت Pod.
توجه داشته باشید که supplementalGroupsPolicy: Strict نیاز به runtime CRI دارد که از این ویژگی پشتیبانی کند. برخی runtimeهایی که پشتیبانی میکنند و نسخهٔ حداقلی موردنیاز:
containerd: v2.0 یا بالاتر CRI-O: v1.31 یا بالاتر
برای تشخیص اینکه آیا runtime از این ویژگی پشتیبانی میکند میتوانید به فیلد .status.features.supplementalGroupsPolicy در Node status نگاه کنید.
این ویژگی همچنین وضعیت کاربری پروسس اول کانتینر را در .status.containerStatuses[].user.linux ثبت میکند تا بتوانید بهصورت شفاف ببینید چه uid/gidهایی پیوست شدهاند. نمونهٔ status:
status:
containerStatuses:
- name: ctr
user:
linux:
uid: 1000
gid: 3000
supplementalGroups:
- 3000
- 4000
جمعبندی و بهترین عملها 👍: در زمان ارتقا به v1.35 یا راهاندازی کلاستر جدید، پادهای خود را طوری آماده کنید که supplemental groups بهوضوح در Pod spec اعلام شوند (نه در تصویر). اگر نیاز به حذف عضویتهای ضمنی دارید، از supplementalGroupsPolicy: Strict استفاده کنید و از runtime مناسب اطمینان حاصل نمایید. همچنین همیشه برای کاهش ریسک تغییر هویت پروسسها، تنظیمات securityContext و سیاستهای Pod را سختگیرانه نگه دارید.
این پیشرفت توسط SIG Node توسعه یافته و اگر نظر یا تجربهای در این زمینه دارید، به اشتراک بگذارید — جامعه مشتاق شنیدن تجربههای عملی شماست 🚀.
برای مطالعهٔ عمیقتر: KEP-3619 (Fine-grained SupplementalGroups control).