containers-signature(5) راهنمای لینوکس containers-signature(5)

containers-signature - ساختار و قالب امضای کانتینر

این سند ساختار و قالب امضاهای کانتینر را بر اساس پیاده‌سازی بسته go.podman.io/image/v5/signature شرح می‌دهد.

بیشتر کاربران باید بتوانند این امضاها را با استفاده از بسته go.podman.io/image/v5/signature (ترجیحاً از طریق رابط سطح بالاتر signature.PolicyContext) به کار ببرند، بدون اینکه نیاز به درگیر شدن با جزئیات ساختار شرح داده شده در زیر داشته باشند. این مستندات عمدتاً برای نگهدارندگان بسته و امکان‌پذیر ساختن پیاده‌سازی‌های مستقل فراهم شده است.

امضا یک ادعای احراز هویت‌شده سرتاسری (end-to-end) فراهم می‌کند مبنی بر اینکه یک ایمیج کانتینر توسط یک طرف مشخص (به عنوان مثال، سازنده ایمیج به عنوان اثر خود، یک سیستم ساخت خودکار به عنوان نتیجه ساخت خودکار، یا بخش فناوری اطلاعات شرکت که ایمیج را برای محیط عملیاتی تایید می‌کند) تحت یک هویت مشخص (به عنوان مثال، یک ایمیج پایه سیستم‌عامل / برنامه‌ای خاص همراه با نسخه‌ای مشخص) تایید شده است.

امضای کانتینر شامل یک امضای رمزنگاری‌شده است که هویت امضاکننده ایمیج را مشخص و احراز می‌کند، و به عنوان بار داده (payload) امضاشده یک سند JSON را حمل می‌نماید. سند JSON ایمیج امضاشده را شناسایی می‌کند، مدعی هویت خاصی برای ایمیج می‌شود و در صورت لزوم، حاوی اطلاعات دیگری درباره ایمیج است.

امضاها ایمیج کانتینر (لایه‌ها، پیکربندی، مانیفست و...) را تغییر نمی‌دهند؛ برای مثال، وجود آن‌ها هش مانیفست (manifest digest) را که برای شناسایی ایمیج در سرورهای docker/distribution استفاده می‌شود تغییر نمی‌دهد؛ بلکه امضاها با یک ایمیج تغییرناپذیر (immutable) مرتبط می‌شوند. یک ایمیج می‌تواند هر تعداد امضا داشته باشد، بنابراین سیستم‌های توزیع امضا «باید» (SHOULD) از اتصال بیش از یک امضا به یک ایمیج پشتیبانی کنند.

امضای کانتینر در هنگام توزیع، یک داده باینری (blob) است که حاوی یک امضای رمزنگاری در یک قالب استاندارد صنعتی است و بار داده JSON امضاشده را حمل می‌کند (یعنی این داده حاوی هم سند JSON و هم امضای سند JSON است؛ این یک «امضای جداگانه» (detached signature) با داده‌های مستقل حاوی سند JSON و امضای رمزنگاری نیست).

در حال حاضر تنها قالب امضای رمزنگاری تعریف‌شده، امضای OpenPGP (RFC 4880) است، اما ممکن است در آینده قالب‌های دیگری اضافه شوند. (این داده حاوی متادیتایی که قالب امضای رمزنگاری را مشخص کند نیست. انتظار می‌رود که بیشتر قالب‌ها به اندازه کافی خودتوصیف‌گر باشند تا نیازی به این کار نباشد و کلید عمومی مورد انتظار پیکربندی‌شده، نشانه دیگری از قالب امضای رمزنگاری مورد انتظار ارائه دهد. در صورت لزوم، چنین متادیتایی ممکن است در آینده برای قالب‌های امضای رمزنگاری جدید اضافه شود.)

مصرف‌کنندگان امضای کانتینر «باید» (SHOULD) امضای رمزنگاری را پیش از هرگونه تجزیه یا پردازش بار داده JSON، با یک یا چند کلید عمومی مورد اعتماد (برای مثال تعریف‌شده در فایل خط‌مشی اعتبارسنجی امضای policy.json ⟨containers-policy.json.5.md⟩) اعتبارسنجی کنند؛ به‌ویژه اگر اعتبارسنجی امضای رمزنگاری ناموفق بود، «باید» بدون حتی شروع پردازش بار داده JSON، پردازش امضای کانتینر را متوقف نمایند.

(مصرف‌کنندگان «می‌توانند» (MAY) هویت کلید امضاکننده و سایر متادیتاها را بدون تایید امضا از امضای رمزنگاری و بار داده JSON استخراج کنند، در صورتی که هدف، مدیریت داده‌های امضا باشد؛ برای مثال، جهت فهرست کردن نویسندگان و هویت‌های ایمیج مربوط به امضاهای متصل به یک ایمیج کانتینر منفرد؛ در این صورت، آن‌ها «باید» خروجی چنین پردازشی را به گونه‌ای طراحی کنند که خطر اعتماد کاربران به خروجی یا استفاده از آن برای تصمیم‌گیری‌های خط‌مشی درباره ایمیج به حداقل برسد.)

هنگام اعتبارسنجی یک امضای رمزنگاری در قالب OpenPGP، مصرف‌کننده «الزاماً باید» (MUST) حداقل جنبه‌های زیر از امضا را تایید کند (مشابه آنچه بسته go.podman.io/image/v5/signature انجام می‌دهد):

  • داده «الزاماً باید» یک «پیام امضاشده» (Signed Message) طبق تعریف RFC 4880 بخش 11.3 باشد (به عنوان مثال، «الزاماً نباید» یک «پیام متنی ساده» امضانشده، یک «امضای متنی واضح» (Cleartext Signature) طبق تعریف RFC 4880 بخش 7، یا هر قالب غیر امضایی دیگری باشد، و «الزاماً نباید» از زره اسکی (ASCII Armor) طبق تعریف RFC 4880 بخش 6 استفاده کند).
  • داده «الزاماً نباید» حاوی بیش از یک «بسته امضا» (Signature Packet) طبق تعریف RFC 4880 بخش 5.2 باشد.
  • امضا «الزاماً باید» توسط یک کلید مورد انتظار و مورد اعتماد برای این منظور (و برای ایمیج کانتینر خاص) ایجاد شده باشد.
  • امضا «الزاماً باید» به درستی قالب‌بندی شده باشد و اعتبارسنجی رمزنگاری را با موفقیت پشت سر بگذارد.
  • امضا «الزاماً باید» بار داده JSON موجود را به درستی احراز هویت کند (به‌ویژه تجزیه بار داده JSON «الزاماً نباید» پیش از احراز هویت کامل رمزنگاری بار داده آغاز شود).
  • امضا «الزاماً نباید» منقضی شده باشد.

مصرف‌کننده «باید» آزمون‌هایی برای کد اعتبارسنجی خود داشته باشد که تایید کند امضاهایی که در هر یک از موارد فوق مردود می‌شوند، رد خواهند شد.

بار داده امضای رمزنگاری یک سند JSON است (RFC 7159). مصرف‌کنندگان «باید» (SHOULD) آن را بسیار سخت‌گیرانه تجزیه کنند و هر امضایی را که ناقض قالب مورد انتظار باشد (برای مثال، فیلدهای مفقود، انواع داده نامعتبر برای اعضا) یا بتواند به طور مبهم تفسیر شود (برای مثال، عضوی تکراری در یک شیء JSON) رد نمایند.

هرگونه نقض قالب JSON یا سایر الزامات این سند در صورتی «می‌تواند» (MAY) پذیرفته شود که بتوان تشخیص داد سند JSON توسط یک پیاده‌سازی نادرستِ شناخته‌شده ایجاد شده است (به بخش ⟨#optionalcreator⟩ در زیر مراجعه کنید) و معنای سند نامعتبر، همان‌گونه که توسط چنین پیاده‌سازی ایجاد شده، شفاف باشد.

مقدار سطح بالای سند JSON «الزاماً باید» (MUST) یک شیء JSON با دقیقاً دو عضو critical و optional باشد که هر یک خود یک شیء JSON هستند.

شیء critical «الزاماً باید» حاوی یک عضو type باشد که سند را به عنوان امضای کانتینر شناسایی کند (مطابق تعریف زیر در ⟨#criticaltype⟩) و مصرف‌کنندگان امضا «الزاماً باید» امضاهایی را که فاقد این عضو هستند یا مقدار این عضو با مقدار مورد انتظار مطابقت ندارد، رد کنند.

جهت اطمینان از سازگاری رو به جلو (امکان پذیرش یا رد صحیح امضاهای ایجادشده در تاریخ‌های بعدی با پسوندهای احتمالی این قالب توسط مصرف‌کنندگان قدیمی‌تر امضا)، مصرف‌کنندگان «الزاماً باید» امضا را در صورتی که شیء critical یا هر یک از زیر‌اشیای آن حاوی هر عضو یا مقدار داده ناشناخته، پشتیبانی‌نشده، نامعتبر، یا به هر نحو دیگری غیرمنتظره باشد، رد کنند. این مورد حداقل شامل اعضای ناشناخته در یک شیء JSON یا انواع نادرست اعضای مورد انتظار است.

به همین دلیل، مصرف‌کنندگان «باید» هر عضوی با نام ناشناخته در شیء optional را بپذیرند، و «می‌توانند» امضاهایی را که در آن‌ها عضو شیء شناخته‌شده ولی پشتیبانی‌نشده است، یا مقدار عضو پشتیبانی‌نشده است، قبول کنند. با این حال مصرف‌کنندگان همچنان «باید» امضاهایی را که در آن‌ها عضوی از شیء optional پشتیبانی می‌شود اما مقدار آن به عنوان نامعتبر شناخته شده است، رد کنند.

یک نمونه از قالب کامل به شرح زیر است و توضیحات تفصیلی در ادامه می‌آید. جهت تاکید مجدد، مصرف‌کنندگان امضا «باید» اعتبارسنجی رمزنگاری موفقیت‌آمیز را انجام دهند، و همان‌طور که در بالا شرح داده شد، «الزاماً باید» داده‌های غیرمنتظره در شیء critical یا در شیء سطح بالا را رد کنند.

{
    "critical": {
        "type": "atomic container signature",
        "image": {
            "docker-manifest-digest": "sha256:817a12c32a39bbe394944ba49de563e085f1d3c5266eb8e9723256bc4448680e"
        },
        "identity": {
            "docker-reference": "docker.io/library/busybox:latest"
        }
    },
    "optional": {
        "creator": "some software package v1.0.1-35",
        "timestamp": 1483228800,
    }
}

این عضو «الزاماً باید» یک شیء JSON حاوی داده‌های حیاتی برای ارزیابی صحیح اعتبار یک امضا باشد.

مصرف‌کنندگان «الزاماً باید» هر امضایی را که در آن شیء critical حاوی هرگونه عضو یا داده ناشناخته، پشتیبانی‌نشده، نامعتبر یا به هر شکل دیگر غیرمنتظره باشد، رد کنند.

این عضو «الزاماً باید» یک رشته با مقدار دقیقاً برابر با atomic container signature (سه کلمه، شامل فاصله‌ها) باشد.

مصرف‌کنندگان امضا «الزاماً باید» امضاهایی را که فاقد این عضو هستند یا این عضو دقیقاً مقدار مورد انتظار را ندارد، رد کنند.

(مصرف‌کنندگان «می‌توانند» از امضاهایی با مقداری متفاوت برای عضو type، در صورتی که در آینده تعریف شود، پشتیبانی کنند؛ در این صورت، باقی سند JSON بر اساس قواعد تعریف‌کننده آن مقدار خاص از critical.type تفسیر می‌شود، نه بر اساس این سند.)

این عضو «الزاماً باید» یک شیء JSON باشد که ایمیج کانتینر مربوط به این امضا را مشخص می‌کند.

مصرف‌کنندگان «الزاماً باید» هر امضایی را که در آن شیء critical.image حاوی هرگونه عضو یا داده ناشناخته، پشتیبانی‌نشده، نامعتبر یا به هر نحو دیگر غیرمنتظره باشد، رد کنند.

(در حال حاضر تنها روش docker-manifest-digest برای شناسایی یک ایمیج کانتینر تعریف شده است؛ ممکن است در آینده روش‌های جایگزینی برای آن تعریف شود، اما مصرف‌کنندگان موجود موظفند امضاهایی را که از قالب‌های پشتیبانی‌نشده استفاده می‌کنند، رد کنند.)

این عضو «الزاماً باید» یک رشته JSON در قالب رشته‌ای github.com/opencontainers/go-digest.Digest باشد.

مقدار این عضو «الزاماً باید» با مانیفست ایمیج کانتینر امضاشده، همان‌گونه که در سامانه آدرس‌دهی مانیفست docker/distribution پیاده‌سازی شده، مطابقت داشته باشد.

مصرف‌کننده امضا «باید» هش مانیفست را پیش از هرگونه پردازش دیگر بر روی محتویات مانیفست ایمیج (مانند تجزیه بیشتر مانیفست یا بارگیری لایه‌های ایمیج)، در برابر یک امضای کاملاً تاییدشده اعتبارسنجی کند.

نکات پیاده‌سازی:

  • مانیفست یک ایمیج کانتینر واحد ممکن است با استفاده از الگوریتم‌های مختلف دارای چندین مقدار معتبر هش مانیفست باشد.
  • برای مانیفست‌های نسخه 1 «امضاشده» در docker/distribution ⟨https://github.com/docker/distribution/blob/master/docs/spec/manifest-v2-1.md⟩، هش مانیفست به بار داده امضای وب JSON اعمال می‌شود، نه به داده خام مانیفست.

این عضو «الزاماً باید» یک شیء JSON باشد که هویت ادعاشده ایمیج (معمولاً کاربرد ایمیج یا برنامه، به همراه اطلاعات نسخه) را به گونه‌ای که توسط نویسنده امضا ادعا شده است، مشخص کند.

مصرف‌کنندگان «الزاماً باید» هر امضایی را که در آن شیء critical.identity حاوی هرگونه عضو یا داده ناشناخته، پشتیبانی‌نشده، نامعتبر یا به هر نحو دیگر غیرمنتظره باشد، رد کنند.

(در حال حاضر تنها روش docker-reference برای ادعای هویت/کاربرد ایمیج تعریف شده است؛ ممکن است در آینده روش‌های جایگزین تعریف شوند، اما مصرف‌کنندگان موجود موظفند امضاهایی را که از قالب‌های پشتیبانی‌نشده استفاده می‌کنند، رد نمایند.)

این عضو «الزاماً باید» یک رشته JSON در قالب رشته‌ای github.com/docker/distribution/reference و با استفاده از همان معناشناسی نرمال‌سازی (که در آن به عنوان مثال busybox:latest معادل docker.io/library/busybox:latest است) باشد. اگر معناشناسی نرمال‌سازی امکان بازنمایی‌های متنی متعددی از هویت ادعاشده با معنای معادل را بدهد، عضو critical.identity.docker-reference «باید» از شکل کاملاً صریح (شامل نام کامل میزبان و فضاهای نام) استفاده کند.

مقدار این عضو «الزاماً باید» با هویت/کاربرد ایمیج مورد انتظار مصرف‌کننده امضای ایمیج و خود ایمیج مطابقت داشته باشد (مجدداً با در نظر گرفتن معناشناسی نرمال‌سازی docker/distribution/reference).

در متداول‌ترین حالت، این بدان معناست که مقدار critical.identity.docker-reference باید برابر با ارجاع docker/distribution مورد استفاده برای اشاره به ایمیج یا دریافت آن باشد. با این حال، بسته به برنامه کاربردی خاص، کاربران یا مدیران سیستم ممکن است تطابق‌های عمومی‌تر را بپذیرند (برای مثال نادیده گرفتن مقدار تگ در امضا هنگام دریافت تگ :latest یا هنگام ارجاع به یک ایمیج از طریق هش مانیفست)، یا ممکن است به مقادیر critical.identity.docker-reference با یک فضای نام کاملاً متفاوت نسبت به ارجاع استفاده‌شده برای اشاره/دریافت ایمیج نیاز داشته باشند (برای مثال نیاز به مقدار critical.identity.docker-reference که نشان دهد ایمیج از یک تامین‌کننده مشخص آمده است، در حالی که ایمیج از یک آینه داخلی شرکتی برای ایمیج‌های تاییدشده دریافت می‌شود). نرم‌افزاری که این اعتبارسنجی را انجام می‌دهد «باید» به کاربران اجازه دهد چنین خط‌مشی‌هایی را با استفاده از قالب فایل خط‌مشی اعتبارسنجی امضای policy.json ⟨containers-policy.json.5.md⟩ تعریف نمایند.

مقدار critical.identity.docker-reference «باید» شامل یک تگ یا یک شناسه یکتای هش (digest) باشد؛ در اغلب موارد، «باید» ترجیحاً به جای هش از یک تگ استفاده شود (همچنین به مقدار پیش‌فرض در ⟨containers-policy.json.5.md#signedby⟩ مراجعه کنید).

این عضو «الزاماً باید» یک شیء JSON باشد.

مصرف‌کنندگان «باید» هر عضوی با نام ناشناخته در شیء optional را بپذیرند، و «می‌توانند» امضایی را که در آن عضو شیء شناخته‌شده ولی پشتیبانی‌نشده است، یا مقدار عضو معتبر اما پشتیبانی‌نشده است، قبول کنند. با این حال مصرف‌کنندگان همچنان «باید» هر امضایی را که در آن عضوی از شیء optional پشتیبانی می‌شود اما مقدار آن نامعتبر شناخته شده است، رد کنند.

در صورت وجود، این عضو «الزاماً باید» یک رشته JSON باشد که نام و نسخه نرم‌افزاری را که امضا را ایجاد کرده است، مشخص کند (شناسایی پیاده‌سازی نرم‌افزاری سطح پایین؛ نه فراخواننده سطح بالا).

محتوای این رشته به طور دقیق تعریف نشده است؛ با این حال هر پیاده‌سازی ایجادکننده امضای کانتینر:

  • «باید» محتوا را به گونه‌ای تعریف کند که نرم‌افزار را در عمل به طور شفاف و بدون ابهام مشخص نماید (برای مثال «باید» شامل نام نرم‌افزار باشد، نه فقط شماره نسخه).
  • «باید» از فرآیند ساخت و نسخه‌گذاری استفاده کند که تضمین نماید هر زمان قالب یا معناشناسی امضای تولیدشده به هر نحوی تغییر کرد، محتوای این رشته (مانند شماره نسخه درج‌شده) نیز تغییر یابد؛ نباید این امکان وجود داشته باشد که دو پیاده‌سازی با قالب یا معناشناسی متفاوت، مقدار optional.creator یکسانی داشته باشند.
  • «باید» از قالبی استفاده کند که تجزیه آن در نرم‌افزار نسبتاً آسان باشد (احتمالاً با استفاده از عبارت باقاعده یا regexp)، و شناسایی بازه‌ای از نسخه‌های یک پیاده‌سازی خاص را به اندازه کافی آسان نماید (برای مثال نسخه پیاده‌سازی «نباید» فقط یک هش گیت باشد، زیرا ترتیب مشخصی ندارند؛ رشته باید حاوی یک شماره نسخه یا حداقل تاریخ کامیت باشد).

مصرف‌کنندگان امضای کانتینر «می‌توانند» مقادیر خاص یا مجموعه‌ای از مقادیر optional.creator (احتمالاً همراه با optional.timestamp) را شناسایی کنند، و «می‌توانند» پردازش امضا را بر اساس این مقادیر تغییر دهند (معمولاً برای سازگاری با موارد نقض این مشخصات در نسخه‌های قبلی نرم‌افزار امضاکننده که امکان رفع آن‌ها به گذشته وجود ندارد)، تا زمانی که معنای سند نامعتبر به وجود آمده توسط چنین پیاده‌سازی، روشن باشد.

اگر مصرف‌کنندگان امضا رفتار خود را بر اساس مقدار optional.creator تغییر دهند، «باید» مراقب باشند که نحوه پردازش امضا با مصرف‌کنندگانی که اعتبارسنجی را به طور سخت‌گیرانه انجام می‌دهند، ناسازگار نباشد. (یعنی قابل قبول است که یک مصرف‌کننده امضایی را بر اساس مقدار خاصی از optional.creator بپذیرد در حالی که سایر پیاده‌سازی‌ها آن را کاملاً رد می‌کنند، اما بسیار نامطلوب است که دو نوع پیاده‌سازی در شرایط متفاوت و متناقض امضا را قبول کنند.)

در صورت وجود، این عضو «الزاماً باید» یک عدد JSON باشد که به عنوان یک عدد صحیح ۶۴ بیتی قابل نمایش باشد، و زمان ایجاد امضا را بر حسب تعداد ثانیه‌های سپری‌شده از مبدأ یونیکس (۱ ژانویه ۱۹۷۰، 00:00 UTC) مشخص کند.

مارس ۲۰۱۷ Containers