WIUNIX ACADEMY
راهاندازی رجیستری خصوصی Docker با HTTPS و Nginx
صفحهٔ 3 از 5؛ مراحل قبلی و پیشنیازها را پیش از ادامه مرور کن.
آموزش متناسب با محیط تو
کجا اجرا میکنی؟
سیستمعامل و نسخه را انتخاب کن تا مراحل، دستورها و راهحلها برای همان محیط نمایش داده شوند.
آموزش متناسب با مقادیر تو
تنظیمات این آموزش
مقادیر نمونه را برای محیط خودت تنظیم کن؛ متن و دستورهای مرتبط با هم تغییر میکنند. رمز، کلید خصوصی و توکن وارد نکن. مقادیر فقط در همین زبانه نگهداری میشوند و به سرور یا لینک اشتراکگذاری فرستاده نمیشوند. پیش از اجرا، DNS، گواهیها و سیاست شبکهٔ واقعی را بررسی کن.
آیپی، دامنه یا پورت مثالها با محیط تو فرق دارد؟ دکمهٔ زیر را باز کن، مقادیر را تغییر بده و «اعمال در آموزش» را بزن؛ سپس دستورهای بهروزشده را کپی کن.
تنظیم مقادیر برای محیط من8 مقدار قابلتغییر
قدم بعدی
گواهی معتبر موجود را در مسیر محافظتشده بگذارید
با روش امن انتقال یا ویرایشگر root، زنجیرهٔ گواهی معتبر موجود و کلید سرویس را در دو فایل زیر قرار دهید. هر دو باید فایل واقعی و متعلق به root باشند؛ کلید 0600، پوشهٔ TLS برابر 0700 و زنجیرهٔ عمومی 0644 باشد. کلید را در فرم مرورگر وارد نکنید و برای رفع خطای اعتماد، گواهی عمومی خودامضا نسازید.
VM رجیستری
sudo python3 - <<'PY'
import os
for name in ('fullchain.pem','privkey.pem'):
f='/srv/academy-registry/tls/'+name
fd=os.open(f,os.O_WRONLY|os.O_CREAT|os.O_EXCL|os.O_NOFOLLOW,0o600)
os.close(fd)
PY
sudo nano '/srv/academy-registry/tls/fullchain.pem' '/srv/academy-registry/tls/privkey.pem'
sudo chmod 0644 '/srv/academy-registry/tls/fullchain.pem'
فایلهای خالی با زنجیره و کلید معتبر پر شدهاند؛ کلید خصوصی نمایش داده نمیشود.
قدم بعدی
نام دامنه، انقضا و تطبیق کلید را کنترل کنید
این کنترلها نام دامنه، باقیماندن حداقل هفت روز اعتبار و برابر بودن کلید عمومی را بررسی میکنند؛ اعتماد تمام کلاینتها را ثابت نمیکنند. پس از فعالکردن HTTPS، اتصال را از کلاینت تمیز هم بسنجید. در تمدید، فقط موفقیت ابزار صدور کافی نیست؛ گواهی واقعاً سروشده پس از reload را نیز بررسی کنید.
VM رجیستری
sudo openssl x509 -in '/srv/academy-registry/tls/fullchain.pem' -noout -checkhost 'registry.example.net'
sudo openssl x509 -in '/srv/academy-registry/tls/fullchain.pem' -noout -checkend 604800
sudo python3 - <<'PY'
import subprocess
base='/srv/academy-registry/tls/'
a=subprocess.check_output(['openssl','x509','-in',base+'fullchain.pem','-pubkey','-noout'])
b=subprocess.check_output(['openssl','pkey','-in',base+'privkey.pem','-pubout'])
assert a==b, 'Certificate and private key do not match'
print('Public-key match: OK')
PY
نام و زمان اعتبار درست است و دو کلید عمومی تطبیق دارند.
قدم بعدی
Nginx را اعتبارسنجی و HTTPS را فعال کنید
فایل سایت باید تازه باشد. اگر تست syntax شکست بخورد، فقط همین فایل به recovery منتقل میشود و تنظیمات جاری سرویس اجراشده تغییر نمیکند. شکست reload را بررسی و فایل تازه را برگردانید؛ restart سرویسهای دیگر راهحل نیست. بازکردن TCP443 باید طبق سیاست شبکهٔ خودتان انجام شود؛ این دستورها فایروال را عوض نمیکنند.
پاسخ سالم بدون ورود، 401 همراه Basic challenge و هدر registry/2.0 است. پاسخ 200 بدون رمز برای این طراحی خطای امنیتی محسوب میشود. مسیر /v2/ را به صفحهٔ ورود مرورگری یا SSO ریدایرکت نکنید.
VM رجیستری
set -eu
sudo test ! -e '/etc/nginx/conf.d/academy-registry.conf'
sudo test ! -L '/etc/nginx/conf.d/academy-registry.conf'
sudo python3 - <<'PY'
import os,stat
from pathlib import Path
src=Path('/srv/academy-registry/config/nginx.conf')
assert stat.S_ISREG(src.lstat().st_mode) and src.stat().st_uid==0
fd=os.open('/etc/nginx/conf.d/academy-registry.conf',os.O_WRONLY|os.O_CREAT|os.O_EXCL|os.O_NOFOLLOW,0o644)
with os.fdopen(fd,'wb') as out: out.write(src.read_bytes())
os.chmod('/etc/nginx/conf.d/academy-registry.conf',0o644)
PY
if sudo nginx -t; then
sudo systemctl reload nginx
else
sudo mv '/etc/nginx/conf.d/academy-registry.conf' '/srv/academy-registry/recovery/failed-nginx.conf'
exit 1
fi
curl --silent --show-error --dump-header - --output /dev/null 'https://registry.example.net/v2/'
تست و reload موفقاند و HTTPS معتبر بدون رمز، challenge و 401 میدهد.
قدم بعدی
ورود Docker را با helper انجام دهید
روی کلاینت لینوکسی و با کاربر عادی اجرا کنید. pass، کلید GPG و helper رسمی باید از قبل آماده باشند. پوشهٔ تازهٔ کلاینت فقط نگاشت helper را در JSON مینویسد؛ رمز را در درخواست تعاملی خصوصی Docker وارد کنید. اگر helper یا اعتماد گواهی مشکل دارد، همان را رفع کنید و ذخیرهٔ رمز در JSON را جایگزین نکنید.
کلاینت لینوکسی
set -eu
command -v docker-credential-pass
pass ls >/dev/null
python3 - <<'PY'
import json, os
from pathlib import Path
p=Path.home()/'.config'/'academy-registry-client'
assert not p.is_symlink() and not p.exists(), 'Choose a fresh client directory'
p.parent.mkdir(mode=0o700,exist_ok=True)
assert not p.parent.is_symlink()
p.mkdir(mode=0o700)
f=p/'config.json'
with f.open('x',encoding='utf-8') as out:
json.dump({'credHelpers':{'registry.example.net':'pass'}},out)
os.chmod(f,0o600)
print('Only helper routing written; no password in JSON')
PY
docker --config "$HOME/.config/academy-registry-client" login 'registry.example.net' --username 'academy-publisher'
ورود موفق است و JSON فقط مسیر helper دارد، نه رمز یا auth ذخیرهشده.
قدم بعدی
یک ایمیج آزمایشی بدون اطلاعات حساس push کنید
کلاینت در پوشهای تازه ایمیج کوچکی با یک فایل متنی میسازد. این ایمیج scratch برنامهٔ اجرایی ندارد و فقط برای انتقال است. digest نهایی manifest را در رکورد غیرمحرمانه ثبت کنید. از ایمیج حاوی کلید، رمز یا دادهٔ واقعی برای آزمون استفاده نکنید.
کلاینت لینوکسی
set -eu
test ! -e "$HOME/academy-registry-image"
mkdir -m 0700 "$HOME/academy-registry-image"
printf 'WIUNIX Academy registry pilot\n' > "$HOME/academy-registry-image/marker.txt"
printf 'FROM scratch\nCOPY marker.txt /marker.txt\n' > "$HOME/academy-registry-image/Dockerfile"
docker --config "$HOME/.config/academy-registry-client" build \
--tag 'registry.example.net/academy/academy-registry:pilot' "$HOME/academy-registry-image"
docker --config "$HOME/.config/academy-registry-client" push 'registry.example.net/academy/academy-registry:pilot'
push کامل میشود و digest نهایی sha256 نمایش داده میشود.
قدم بعدی
pull را از کلاینت مستقل بسنجید
روی کلاینت دوم که این ایمیج را ندارد، ابتدا helper و ورود را جدا آماده و سپس pull کنید. RepoDigest باید با digest ثبتشدهٔ push برابر باشد. کش کلاینت اول شاهد کافی نیست. برای استقرار، مرجع شامل digest ثبتشده را به کار ببرید؛ برابری digest بهتنهایی ایمنی یا اصالت ناشر را ثابت نمیکند.
کلاینت لینوکسی
docker --config "$HOME/.config/academy-registry-client" pull 'registry.example.net/academy/academy-registry:pilot'
docker image inspect 'registry.example.net/academy/academy-registry:pilot' --format '{{json .RepoDigests}}'
ایمیج روی کلاینت تمیز دریافت میشود و digest با رکورد push برابر است.