مدیریت سکرت‌ها در GitHub Actions یعنی جدا کردن اطلاعات حساس از کد و تزریق آن‌ها فقط در زمان اجرا. یک توکن API یا رمز پایگاه داده که در workflow لو برود، می‌تواند کل زیرساخت را در معرض خطر قرار دهد. GitHub سه سطح سکرت ارائه می‌دهد: repository، environment و organization؛ هرکدام برای سناریوی متفاوتی طراحی شده‌اند. این نوشته مسیر کامل از تعریف سکرت تا چرخش، ممیزی و جایگزین‌های امن‌تر مثل OIDC را پوشش می‌دهد. تمرکز اصلی روی تصمیم‌هایی است که در پروژه‌های واقعی بیشترین اثر را دارند.

بارها دیده‌ام که یک تیم با دقت روی کد کار می‌کند، تست‌ها را سبز نگه می‌دارد و بعد در یک لحظه، یک توکن لو می‌رود و همه‌چیز به هم می‌ریزد. سکرت‌ها همان نقطه‌ی حساسی هستند که بیشترین آسیب را از کم‌توجهی می‌بینند و کمترین توجه را در کدبازی دریافت می‌کنند.

چرا سکرت‌ها یک مسئله‌ی امنیتی جدی هستند

یک workflow در GitHub Actions اغلب به منابع خارجی متصل می‌شود: رجیستری پکیج، سرور استقرار، پایگاه داده، سرویس ابری یا API شخص ثالث. هر یک از این اتصال‌ها نیازمند اعتبارنامه است. اگر این اعتبارنامه‌ها در کد باشند، در تاریخچه‌ی گیت باقی می‌مانند و حتی اگر بعداً حذف شوند، در commit‌های قدیمی قابل بازیابی هستند.

افشای یک توکن API می‌تواند به دسترسی غیرمجاز به داده، مصرف غیرمنتظره‌ی سرویس یا حتی حذف کامل منابع منجر شود. هزینه‌ی چنین حادثه‌ای فقط مالی نیست؛ اعتماد کاربران و اعتبار سازمان هم آسیب می‌بیند. به همین دلیل، مدیریت سکرت‌ها بخشی از استراتژی امنیتی است، نه یک کار جانبی. اصول کلی این حوزه در بهترین روش‌های امنیت وب کدامند؟ به‌تفصیل بررسی شده است.

سکرتی که در کد قرار بگیرد، دیگر سکرت نیست؛ یک اطلاع عمومی با تأخیر است.

نکته‌ی مهم این است که GitHub خودش هم گاهی سکرت‌ها را تشخیص می‌دهد. قابلیت Secret Scanning برای برخی الگوهای شناخته‌شده هشدار می‌دهد، اما این مکانیزم جامع نیست و نباید جایگزین انضباط تیمی شود.

سه سطح سکرت در GitHub و کاربرد هرکدام

GitHub سه سطح مجزا برای سکرت‌ها فراهم می‌کند و انتخاب سطح درست، بخشی از طراحی امنیتی است.

سطحمحدوده‌ی دسترسیکاربرد مناسب
Repositoryفقط در همان مخزنتوکن‌های مخصوص یک پروژه
Environmentفقط برای workflowهایی که به آن environment اشاره می‌کنندسکرت‌های production با نیاز به تأیید
Organizationقابل اشتراک بین چند مخزن با سیاست دسترسیسکرت‌های مشترک بین پروژه‌ها

سکرت‌های environment قدرتمندتر از آن‌اند که در نگاه اول به نظر می‌رسد. این سطح اجازه می‌دهد قواعدی مثل «نیاز به تأیید دستی» یا «محدود به شاخه‌ی main» را اعمال کنید. برای محیط production، این سطح انتخاب پیشنهادی است، چون سکرت را فقط در لحظه‌ای در اختیار workflow می‌گذارد که همه‌ی شرایط تأیید برقرار باشد.

سکرت‌های organization برای تیم‌هایی مناسب است که چند پروژه‌ی مرتبط دارند. با تعریف یک سکرت در سطح سازمان و اعطای دسترسی به مخازن مشخص، از تکرار و ناهمگونی جلوگیری می‌شود. اما این سطح باید با احتیاط استفاده شود، چون یک اشتباه در تنظیم دسترسی می‌تواند سکرت را در معرض مخازن ناخواسته قرار دهد.

ساخت و مدیریت سکرت‌ها در عمل

ساخت سکرت از طریق رابط وب یا با GitHub CLI انجام می‌شود:

# با GitHub CLI
gh secret set API_TOKEN

# برای یک environment مشخص
gh secret set API_TOKEN --env production

# برای organization
gh secret set API_TOKEN --org my-org

در روش رابط وب، مسیر Settings → Secrets and variables → Actions نقطه‌ی شروع است. بعد از تعریف، مقدار سکرت دیگر قابل مشاهده نیست و فقط می‌توان آن را به‌روزرسانی یا حذف کرد. این محدودیت عمدی است تا حتی اعضای تیم هم نتوانند مقادیر را ببینند.

نام‌گذاری سکرت‌ها باید قاعده‌مند باشد. استفاده از حروف بزرگ و زیرخط، خوانایی را بالا می‌برد: DATABASE_URL، API_TOKEN، AWS_ACCESS_KEY_ID. از نام‌های مبهم مثل KEY1 یا TOKEN بدون پیشوند پرهیز کنید.

متغیرهای غیرحساس (variables) را با سکرت‌ها اشتباه نگیرید. متغیرها برای مقادیری هستند که افشایشان مشکلی ایجاد نمی‌کند، مثل نام محیط یا نسخه‌ی سرویس. سکرت‌ها برای مقادیری هستند که افشایشان فاجعه‌بار است.

استفاده از سکرت‌ها در workflow

در یک workflow، سکرت‌ها از طریق context secrets در دسترس هستند:

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Deploy to server
        env:
          API_TOKEN: ${{ secrets.API_TOKEN }}
        run: ./deploy.sh

تزریق از طریق env انتخاب بهتری از درج مستقیم در خط فرمان است، چون از ثبت شدن مقدار در لاگ جلوگیری می‌کند. اگر سکرت را مستقیماً در دستور بنویسید، ممکن است در خروجی اجرا ظاهر شود و در لاگ باقی بماند.

در GitHub Actions، سکرت‌ها به‌طور خودکار ماسک می‌شوند، اما این ماسک کردن کامل نیست. اگر سکرت را در خروجی به شکلی تغییر دهید — مثلاً با base64 یا تغییر حروف — ممکن است ماسک از کار بیفتد. این نکته در پروژه‌های واقعی چند بار باعث نشت تصادفی شده است.

برای ارتباط با APIهای خارجی، اصول احراز هویت مشابه همان چیزی است که در احراز هویت در API راهنمای انتخاب روش درست توضیح داده شده. تفاوت اینجاست که در CI، سکرت‌ها معمولاً با طول عمر کوتاه و دسترسی محدود تعریف می‌شوند.

ماسک کردن و خطرات نشت تصادفی

GitHub هر سکرت را در لاگ‌ها با *** جایگزین می‌کند، اما این مکانیزم محدودیت‌هایی دارد:

  • اگر سکرت در یک ساختار پیچیده (مثل JSON رمزگذاری‌شده) درج شود، ماسک اعمال نمی‌شود.
  • اگر بخشی از سکرت — مثل نیمه‌ی اول یک توکن — در خروجی ظاهر شود، GitHub آن را تشخیص نمی‌دهد.
  • اگر سکرت در URL یا پارامترهای query قرار بگیرد، ممکن است در لاگ سرور یا ابزار میانی ثبت شود.

برای کاهش ریسک، چند قاعده‌ی عملی وجود دارد. اول، هرگز سکرت را در دستور echo یا print قرار ندهید. دوم، از سکرت‌های با دامنه‌ی محدود استفاده کنید؛ توکنی که فقط به یک repository دسترسی دارد، به‌مراتب کم‌خطرتر از توکنی است که به کل حساب دسترسی دارد. سوم، در صورت امکان، از سکرت‌های کوتاه‌عمر استفاده کنید که پس از یک اجرا باطل می‌شوند.

# اشتباه: سکرت در دستور مستقیم
run: curl -H "Authorization: Bearer ${{ secrets.API_TOKEN }}" https://api.example.com

# درست: تزریق از طریق env
env:
  API_TOKEN: ${{ secrets.API_TOKEN }}
run: curl -H "Authorization: Bearer $API_TOKEN" https://api.example.com

در حالت دوم، اگر دستور خطا بدهد، مقدار سکرت در پیام خطا ظاهر نمی‌شود. این تفاوت کوچک، در عمل تفاوت بزرگی می‌سازد.

چرخش سکرت‌ها و سیاست نگهداشت

چرخش دوره‌ای سکرت‌ها یکی از اصول پایه‌ی امنیت است. سکرتی که ماه‌ها بدون تغییر بماند، در صورت افشا، مدت طولانی در اختیار مهاجم باقی می‌ماند. سیاست چرخش به نوع سکرت بستگی دارد:

  • توکن‌های شخصی: هر ۹۰ روز یا کمتر.
  • کلیدهای سرویس ابری: هر ۶۰ روز با استفاده از IAM برای محدودسازی دسترسی.
  • سکرت‌های استقرار: در هر استقرار production یا پس از هر تغییر تیم.
  • سکرت‌های سازمانی: طبق سیاست امنیتی سازمان، معمولاً ۳۰ تا ۹۰ روز.

در پروژه‌های تیمی، چرخش سکرت باید با هماهنگی انجام شود تا سرویس‌های فعال از دسترس خارج نشوند. یک رویکرد عملی این است که ابتدا سکرت جدید ساخته شود، سپس سرویس‌ها به آن منتقل شوند و در نهایت سکرت قدیمی حذف شود. این الگو به چرخش بدون قطعی معروف است و در پروژه‌های حیاتی ضروری است.

پیگیری تاریخچه‌ی چرخش سکرت‌ها در یک سند داخلی یا ابزار مدیریت سکرت توصیه می‌شود. بدون این پیگیری، سکرت‌هایی که باید چرخیده باشند، به فراموشی سپرده می‌شوند. این موضوع در تیم‌های دورکار اهمیت بیشتری پیدا می‌کند؛ همان‌طور که در بهترین شیوه‌های HRM برای تیم‌های دورکار به اهمیت مستندسازی فرآیندهای تیمی اشاره شده است.

OIDC و احراز هویت بدون کلید

OpenID Connect (OIDC) یک روش مدرن برای اتصال GitHub Actions به سرویس‌های ابری بدون ذخیره‌ی سکرت طولانی‌عمر است. در این روش، GitHub یک توکن کوتاه‌عمر با ادعاهای (claims) مشخص صادر می‌کند و سرویس ابری آن را می‌پذیرد. مزیت اصلی این است که هیچ کلید ثابتی در GitHub ذخیره نمی‌شود.

permissions:
  id-token: write
  contents: read

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/GitHubActionsRole
          aws-region: us-east-1

در این الگو، سرویس ابری به‌جای اعتماد به یک کلید ثابت، به یک شرط مبتنی بر مخزن و شاخه اعتماد می‌کند. این رویکرد، خطر نشت سکرت را به‌طور چشمگیری کاهش می‌دهد و در AWS، GCP و Azure پشتیبانی می‌شود. اصول این نوع احراز هویت با مفاهیمی که در OAuth چیست و چگونه کار می‌کند؟ توضیح داده شده، هم‌خانواده است.

محدودیت OIDC این است که همه‌ی سرویس‌ها از آن پشتیبانی نمی‌کنند. برای سرویس‌های قدیمی‌تر، ناچار به استفاده از سکرت‌های ثابت هستید و در آن صورت، اصول چرخش و محدودسازی دسترسی اهمیت بیشتری پیدا می‌کند.

ممیزی و بررسی دسترسی‌ها

دسترسی به سکرت‌ها باید ممیزی شود. GitHub گزارش‌های audit log ارائه می‌دهد که نشان می‌دهد چه کسی سکرتی را ساخته، تغییر داده یا حذف کرده است. در سطح سازمان، این گزارش‌ها می‌توانند به یک سیستم مرکزی ارسال شوند و برای تحلیل امنیتی استفاده گردند.

در عمل، چند پرسش باید به‌طور دوره‌ای بررسی شوند:

  • کدام سکرت‌ها در ۶ ماه گذشته استفاده نشده‌اند؟
  • کدام سکرت‌ها به مخازنی دسترسی دارند که نباید؟
  • آیا سکرت‌های حساس در سطح environment تعریف شده‌اند یا repository؟
  • آیا اعضای تیم که از سازمان خارج شده‌اند، هنوز به سکرت‌ها دسترسی دارند؟

این ممیزی در پروژه‌هایی که با استانداردهای امنیتی مثل ISO 27001 یا SOC 2 کار می‌کنند، الزامی است. ابزارهای خودکار مثل gh secret list می‌توانند بخشی از این فرآیند را ساده کنند:

# فهرست سکرت‌های مخزن
gh secret list

# فهرست سکرت‌های سازمان
gh secret list --org my-org

# حذف یک سکرت
gh secret delete OLD_TOKEN

سکرت‌ها و اکشن‌های شخص ثالث

استفاده از اکشن‌های شخص ثالث در workflow، یک ریسک امنیتی است. اگر اکشن مورد اعتماد نباشد، می‌تواند سکرت‌ها را بخواند و به خارج ارسال کند. چند قاعده‌ی عملی برای کاهش این ریسک وجود دارد:

  • اکشن‌ها را به یک commit SHA مشخص پین کنید، نه به یک تگ شناور.
  • از اکشن‌های رسمی یا تأییدشده‌ی GitHub استفاده کنید.
  • سکرت‌ها را فقط در stepهایی که واقعاً به آن‌ها نیاز دارند، در دسترس قرار دهید.
  • از permissions در سطح job استفاده کنید تا دسترسی‌ها محدود شوند.
permissions:
  contents: read

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: third-party/action@1a2b3c4d5e6f7g8h9i0j

پین کردن به SHA از این جهت مهم است که تگ‌ها می‌توانند توسط نگه‌دارنده‌ی اکشن جابه‌جا شوند. اگر یک اکشن مورد اعتماد، به‌دلیل نفوذ به حساب نگه‌دارنده، به نسخه‌ی مخرب تغییر کند، پین به SHA از شما محافظت می‌کند. این نوع حملات — که به supply chain attack معروف‌اند — در سال‌های اخیر افزایش یافته و در نوشته‌ی حمله تزریق کد چیست و چگونه دفع می‌شود؟ به آن پرداخته شده است.

اشتباهات رایج در مدیریت سکرت‌ها

  • commit کردن فایل .env: رایج‌ترین و پرهزینه‌ترین اشتباه. این فایل باید در .gitignore باشد.
  • استفاده از سکرت‌های طولانی‌عمر: توکنی که ماه‌ها بدون تغییر می‌ماند، در صورت نشت، مدت طولانی در اختیار مهاجم است.
  • درج سکرت در URL: پارامترهای query در لاگ‌های سرور ثبت می‌شوند و ممکن است در ابزارهای میانی هم ذخیره شوند.
  • اشتراک سکرت بین محیط‌های متفاوت: سکرت production نباید در staging یا development استفاده شود.
  • نادیده گرفتن permissions: بدون محدودسازی، هر step دسترسی کامل به توکن گیت‌هاب دارد.
  • استفاده از اکشن‌های غیرقابل اعتماد: هر اکشن شخص ثالث می‌تواند سکرت‌ها را بخواند.
  • عدم ممیزی دوره‌ای: سکرت‌های فراموش‌شده به‌سرعت به یک بدهی امنیتی تبدیل می‌شوند.
  • بازنویسی تاریخچه بدون چرخش سکرت: اگر سکرتی commit شده، حذف از تاریخچه کافی نیست؛ باید سکرت را باطل کنید.

در صورت لو رفتن یک سکرت، ترتیب اقدامات مهم است. ابتدا سکرت را باطل کنید، سپس سرویس را بررسی کنید، بعد سکرت جدید بسازید و در نهایت لاگ‌های دسترسی را بررسی کنید. بازنویسی تاریخچه گیت یک اقدام ثانویه است و نباید جایگزین باطل کردن فوری شود. اصول این نوع واکنش در اشتباهات رایج در مقابله با حملات سایبری توضیح داده شده است.

پرسش‌های پرتکرار درباره مدیریت سکرت‌ها

آیا سکرت‌ها در forkها در دسترس هستند؟ خیر. GitHub سکرت‌ها را در forkهای public به workflow نمی‌دهد، مگر با تنظیمات خاص. این محدودیت برای جلوگیری از سرقت سکرت توسط PRهای مخرب طراحی شده است.

آیا می‌توان سکرت را بعد از استفاده حذف کرد؟ بله. با gh secret delete NAME یا از رابط وب. اما توجه کنید که حذف سکرت به‌معنای باطل شدن آن در سرویس خارجی نیست؛ باید خود سکرت را در سرویس مبدأ هم باطل کنید.

تفاوت secrets و variables چیست؟ سکرت‌ها رمزگذاری‌شده و ماسک‌شده هستند؛ متغیرها در لاگ‌ها نمایش داده می‌شوند. برای داده‌های غیرحساس از variables و برای داده‌های حساس از secrets استفاده کنید.

آیا می‌توانم سکرت‌ها را بین مخازن سازمان به اشتراک بگذارم؟ بله، از طریق organization secrets. دسترسی به هر مخزن به‌صورت جداگانه تنظیم می‌شود.

آیا OIDC جایگزین کامل سکرت‌ها است؟ نه هنوز. برای سرویس‌هایی که از OIDC پشتیبانی می‌کنند، بله. برای بقیه، ناچار به استفاده از سکرت هستید.

چطور بفهمم یک سکرت لو رفته است؟ GitHub در برخی موارد هشدار می‌دهد، اما بهترین راه، استفاده از سرویس‌های مانیتورینگ سکرت و ممیزی دوره‌ای است. اگر شک دارید، سکرت را باطل کنید.

آیا استفاده از Vault یا AWS Secrets Manager در GitHub Actions ممکن است؟ بله، اما برای دسترسی به خود Vault نیاز به یک سکرت یا OIDC دارید. الگوی رایج این است که یک سکرت bootstrap در GitHub تعریف شود و بقیه‌ی سکرت‌ها در زمان اجرا از Vault گرفته شوند.

آیا سکرت‌ها در لاگ‌های Actions ذخیره می‌شوند؟ مقادیر سکرت‌ها ماسک می‌شوند، اما اگر سکرت را تغییر دهید یا در ساختار پیچیده درج کنید، ممکن است ماسک اعمال نشود. لاگ‌ها به‌طور پیش‌فرض ۹۰ روز نگه‌داری می‌شوند و باید در نظر بگیرید که در این دوره، هرگونه نشت قابل مشاهده است.

لایه‌ی مهندسی و تصمیم‌های معماری

در سطح معماری، مدیریت سکرت یک مسئله‌ی توزیع‌شده با سه محور اصلی است: محرمانگی، یکپارچگی و دسترس‌پذیری. GitHub Actions این سه محور را در یک مدل ساده‌شده پیاده می‌کند، اما در سازمان‌های بزرگ، این مدل به‌سرعت به محدودیت می‌خورد.

الگوی معماری پیشرفته، استفاده از یک سیستم مدیریت سکرت متمرکز مثل HashiCorp Vault است. در این الگو، GitHub Actions فقط یک سکرت bootstrap دارد — معمولاً یک توکن کوتاه‌عمر — که با آن به Vault متصل می‌شود و بقیه‌ی سکرت‌ها را در زمان اجرا دریافت می‌کند. مزیت این معماری، چرخش مرکزی، ممیزی کامل و کنترل دقیق دسترسی است.

از منظر امنیت زنجیره‌ی تأمین (supply chain)، سکرت‌ها فقط یک بخش از تصویر هستند. اکشن‌های شخص ثالث، پکیج‌های npm، imageهای Docker و ابزارهای خط فرمان، همه می‌توانند نقطه‌ی نفوذ باشند. یک استراتژی کامل، همه‌ی این لایه‌ها را پوشش می‌دهد. اصول این رویکرد با آنچه در CVE چیست و چه نقشی در امنیت دارد؟ توضیح داده شده، هم‌راستاست.

در لایه‌ی شبکه، محدودسازی دسترسی سکرت‌ها به IPهای مشخص یک لایه‌ی دفاعی اضافه می‌کند. GitHub Actions از محدوده‌ی IP مشخصی اجرا می‌شود که می‌توان آن را در سرویس‌های خارجی whitelist کرد. این موضوع در سازمان‌هایی که با داده‌های حساس کار می‌کنند، اهمیت بالایی دارد.

نکته‌ی ظریف دیگر، تفکیک محیط‌ها است. سکرت production نباید در staging یا preview قابل دسترس باشد. GitHub environmentها این تفکیک را ممکن می‌کنند، اما نیازمند انضباط در تعریف workflowها هستند. اگر یک workflow به‌اشتباه به environment اشتباه اشاره کند، سکرت نادرست در اختیار آن قرار می‌گیرد. این نوع خطا در تیم‌های بزرگ رایج است و باید با بازبینی دوره‌ای کد و تست‌های خودکار شناسایی شود. 🔐

در نهایت، مدیریت سکرت یک فرآیند است، نه یک ویژگی. ابزارها فقط بخشی از راه‌حل هستند؛ بخش مهم‌تر، فرهنگ تیمی و انضباط مستمر است. بدون بازبینی دوره‌ای و آموزش، حتی بهترین ابزارها هم نمی‌توانند از یک اشتباه انسانی جلوگیری کنند. 🛡️

بستن بحث

سکرت‌ها در GitHub Actions یک نقطه‌ی حساس هستند که کم‌توجهی به آن‌ها می‌تواند هزینه‌ی سنگینی داشته باشد. انتخاب سطح درست سکرت، تزریق از طریق env، چرخش دوره‌ای و استفاده از OIDC در صورت امکان، چهار اصل ساده‌ای هستند که بیشتر ریسک‌ها را پوشش می‌دهند.

اگر تازه شروع کرده‌اید، از همان ابتدا سکرت‌ها را از کد جدا کنید و فایل .env را در .gitignore قرار دهید. اگر روی پروژه‌ی موجود کار می‌کنید، یک ممیزی ساده انجام دهید و سکرت‌های قدیمی یا بی‌استفاده را پاک کنید. این کار کوچک، سطح امنیت را به‌طور محسوس بالا می‌برد.

اگر تجربه‌ای از مواجهه با نشت سکرت یا پیاده‌سازی یک استراتژی مدیریت سکرت در تیم دارید، برایم جالب است بدانید کدام بخش بیشترین چالش را داشت. تجربه‌تان را در دیدگاه‌ها بنویسید؛ به‌خصوص اگر راه‌حل جایگزینی برای مدیریت سکرت‌ها در محیط‌های پیچیده پیدا کرده‌اید.