رمزگذاری در MySQL: Keystore

در انتظار شروع ثبت نام جدید برای دوره "پایگاه اطلاعاتی" ترجمه مقاله مفیدی را برای شما آماده کرده ایم.

رمزگذاری در MySQL: Keystore

رمزگذاری داده های شفاف (TDE) در ظاهر شد سرور Percona برای MySQL و MySQL برای مدتی طولانی. اما آیا تا به حال به این موضوع فکر کرده اید که چگونه زیر هود کار می کند و TDE چه تاثیری می تواند بر سرور شما داشته باشد؟ در این سری از مقالات به نحوه عملکرد داخلی TDE خواهیم پرداخت. بیایید با ذخیره سازی کلید شروع کنیم، زیرا این برای کارکرد هر رمزگذاری لازم است. سپس نگاهی دقیق تر به نحوه کارکرد رمزگذاری در Percona Server برای MySQL/MySQL و ویژگی های اضافی Percona Server for MySQL خواهیم انداخت.

کلید MySQL

Keyring پلاگین هایی هستند که به سرور اجازه می دهند تا کلیدهای یک فایل محلی (keyring_file) یا روی یک سرور راه دور (مانند HashiCorp Vault) را جستجو، ایجاد و حذف کند. کلیدها همیشه به صورت محلی ذخیره می شوند تا سرعت بازیابی آنها افزایش یابد.

پلاگین ها را می توان به دو دسته تقسیم کرد:

  • ذخیره سازی محلی به عنوان مثال، یک فایل محلی (ما به این یک کلید مبتنی بر فایل می گوییم).
  • ذخیره سازی از راه دور. به عنوان مثال، سرور Vault (ما به این یک کلید مبتنی بر سرور می گوییم).

این جداسازی از این جهت مهم است که انواع مختلف فضای ذخیره‌سازی، نه تنها هنگام ذخیره و بازیابی کلیدها، بلکه هنگام اجرای آنها نیز کمی متفاوت عمل می‌کنند.

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

در مورد فروشگاه‌های مبتنی بر سرور (مانند Vault Server)، تنها شناسه کلید و کاربر کلید هنگام راه‌اندازی بارگذاری می‌شوند، بنابراین دریافت همه کلیدها سرعت راه‌اندازی را کاهش نمی‌دهد. کلیدها با تنبلی بارگذاری می شوند. یعنی خود کلید فقط زمانی از Vault بارگیری می شود که واقعاً به آن نیاز باشد. پس از دانلود، کلید در حافظه پنهان ذخیره می شود تا در آینده نیازی به دسترسی به آن از طریق اتصالات TLS به سرور Vault نباشد. در مرحله بعد، بیایید ببینیم چه اطلاعاتی در فروشگاه کلید وجود دارد.

اطلاعات کلیدی شامل موارد زیر است:

  • شناسه کلید - شناسه کلید، به عنوان مثال:
    INNODBKey-764d382a-7324-11e9-ad8f-9cb6d0d5dc99-1
  • نوع کلید - نوع کلید بر اساس الگوریتم رمزگذاری مورد استفاده، مقادیر ممکن: "AES"، "RSA" یا "DSA".
  • طول کلید - طول کلید بر حسب بایت، AES: 16، 24 یا 32، RSA 128، 256، 512 و DSA 128، 256 یا 384.
  • کاربر - صاحب کلید اگر کلید سیستم باشد، مثلاً Master Key، پس این فیلد خالی است. اگر کلیدی با استفاده از keyring_udf ایجاد شود، این فیلد مالک کلید را مشخص می کند.
  • خود کلید

کلید به طور منحصر به فرد توسط جفت شناسایی می شود: key_id، user.

همچنین تفاوت هایی در ذخیره و حذف کلیدها وجود دارد.

ذخیره سازی فایل سریعتر است. ممکن است فکر کنید که یک فروشگاه کلید به سادگی یک بار کلید یک فایل را می نویسد، اما نه، اینجا چیزهای بیشتری در جریان است. هر زمان که تغییری در ذخیره سازی فایل انجام شود، ابتدا یک نسخه پشتیبان از تمام محتوا ایجاد می شود. فرض کنید فایل my_biggest_secrets نام دارد، سپس نسخه پشتیبان my_biggest_secrets.backup خواهد بود. در مرحله بعد، حافظه پنهان تغییر می کند (کلیدها اضافه یا حذف می شوند) و اگر همه چیز موفقیت آمیز باشد، کش به یک فایل بازنشانی می شود. در موارد نادر، مانند خرابی سرور، ممکن است این فایل پشتیبان را مشاهده کنید. بار بعدی که کلیدها بارگیری می شوند (معمولاً پس از راه اندازی مجدد سرور) فایل پشتیبان حذف می شود.

هنگام ذخیره یا حذف یک کلید در حافظه سرور، حافظه باید با دستورات "ارسال کلید" / "درخواست حذف کلید" به سرور MySQL متصل شود.

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

حالا بیایید کمی بیشتر در مورد keyring_file صحبت کنیم. هنگامی که من در حال توسعه keyring_file بودم، همچنین نگران این بودم که چگونه تغییرات keyring_file را در حین اجرای سرور بررسی کنم. در نسخه 5.7 بررسی بر اساس آمار فایل انجام شد که راه حل ایده آلی نبود و در نسخه 8.0 با چکسام SHA256 جایگزین شد.

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

ما قبلاً به سؤالات زیادی در مورد خزانه های کلید پرداخته ایم. با این حال، موضوع مهم دیگری وجود دارد که اغلب فراموش می شود یا به اشتباه درک می شود: اشتراک گذاری کلیدها در سرورها.

منظورم چیست؟ هر سرور (به عنوان مثال، سرور Percona) در کلاستر باید یک مکان جداگانه در سرور Vault داشته باشد که سرور Percona باید کلیدهای خود را در آن ذخیره کند. هر کلید اصلی ذخیره شده در حافظه حاوی GUID سرور Percona در شناسه خود است. چرا مهم است؟ تصور کنید که شما فقط یک Vault Server دارید و همه سرورهای Percona در کلاستر از آن Vault Server استفاده می کنند. مشکل آشکار به نظر می رسد. اگر همه سرورهای Percona از یک Master Key بدون شناسه های منحصر به فرد مانند id = 1، id = 2 و غیره استفاده کنند، آنگاه همه سرورهای خوشه از همان Master Key استفاده می کنند. آنچه GUID ارائه می دهد تمایز بین سرورها است. پس چرا اگر یک GUID منحصر به فرد از قبل وجود داشته باشد، در مورد اشتراک گذاری کلیدها بین سرورها صحبت کنیم؟ افزونه دیگری وجود دارد - keyring_udf. با استفاده از این افزونه، کاربر سرور شما می تواند کلیدهای خود را در سرور Vault ذخیره کند. مشکل زمانی رخ می دهد که یک کاربر برای مثال یک کلید در server1 ایجاد می کند و سپس سعی می کند یک کلید با همان شناسه در server2 ایجاد کند، به عنوان مثال:

--server1:
select keyring_key_store('ROB_1','AES',"123456789012345");
1
--1 значит успешное завершение
--server2:
select keyring_key_store('ROB_1','AES',"543210987654321");
1

صبر کن. هر دو سرور از یک Vault Server استفاده می کنند، آیا نباید تابع keyring_key_store در server2 از کار بیفتد؟ جالب اینجاست که اگر بخواهید همین کار را روی یک سرور انجام دهید، با یک خطا مواجه خواهید شد:

--server1:
select keyring_key_store('ROB_1','AES',"123456789012345");
1
select keyring_key_store('ROB_1','AES',"543210987654321");
0

درست است، ROB_1 از قبل وجود دارد.

ابتدا مثال دوم را مورد بحث قرار می دهیم. همانطور که قبلاً گفتیم، keyring_vault یا هر افزونه keyring دیگری همه شناسه های کلید را در حافظه پنهان می کند. بنابراین پس از ایجاد یک کلید جدید، ROB_1 به server1 اضافه می شود و علاوه بر ارسال این کلید به Vault، کلید نیز به کش اضافه می شود. حالا وقتی می‌خواهیم برای بار دوم همان کلید را اضافه کنیم، keyring_vault بررسی می‌کند که آیا کلید در حافظه پنهان وجود دارد یا خیر و خطا می‌دهد.

در مورد اول وضعیت متفاوت است. Server1 و Server2 کش های جداگانه دارند. پس از افزودن ROB_1 به حافظه پنهان کلید در server1 و سرور Vault، حافظه پنهان کلید در server2 همگام نیست. هیچ کلید ROB_2 در حافظه پنهان سرور1 وجود ندارد. بنابراین، کلید ROB_1 در keyring_key_store و سرور Vault نوشته می‌شود که در واقع مقدار قبلی (!) را بازنویسی می‌کند. اکنون کلید ROB_1 در سرور Vault 543210987654321 است. جالب اینجاست که سرور Vault چنین اقداماتی را مسدود نمی کند و به راحتی مقدار قدیمی را بازنویسی می کند.

اکنون می توانیم ببینیم که چرا پارتیشن بندی سرور در Vault می تواند مهم باشد - زمانی که از keyring_udf استفاده می کنید و می خواهید کلیدها را در Vault ذخیره کنید. چگونه می توان به این جداسازی در سرور Vault دست یافت؟

دو راه برای پارتیشن بندی در Vault وجود دارد. شما می توانید برای هر سرور نقاط مختلف را ایجاد کنید یا از مسیرهای مختلف در یک نقطه نصب استفاده کنید. این به بهترین وجه با مثال ها نشان داده می شود. بنابراین ابتدا به نقاط نصب جداگانه نگاه می کنیم:

--server1:
vault_url = http://127.0.0.1:8200
secret_mount_point = server1_mount
token = (...)
vault_ca = (...)

--server2:
vault_url = http://127.0.0.1:8200
secret_mount_point = sever2_mount
token = (...)
vault_ca = (...)

در اینجا می توانید ببینید که server1 و server2 از نقاط مختلف Mount استفاده می کنند. هنگام تقسیم مسیرها، پیکربندی به صورت زیر خواهد بود:

--server1:
vault_url = http://127.0.0.1:8200
secret_mount_point = mount_point/server1
token = (...)
vault_ca = (...)
--server2:
vault_url = http://127.0.0.1:8200
secret_mount_point = mount_point/sever2
token = (...)
vault_ca = (...)

در این مورد، هر دو سرور از یک نقطه mount "mount_point" استفاده می کنند، اما از مسیرهای متفاوتی استفاده می کنند. هنگامی که اولین راز را در server1 با استفاده از این مسیر ایجاد می کنید، سرور Vault به طور خودکار یک فهرست "server1" ایجاد می کند. برای server2 همه چیز مشابه است. وقتی آخرین راز را در mount_point/server1 یا mount_point/server2 حذف می‌کنید، سرور Vault آن دایرکتوری‌ها را نیز حذف می‌کند. در صورتی که از جداسازی مسیر استفاده می کنید، باید فقط یک نقطه اتصال ایجاد کنید و فایل های پیکربندی را تغییر دهید تا سرورها از مسیرهای جداگانه استفاده کنند. با استفاده از درخواست HTTP می توان نقطه اتصال ایجاد کرد. با استفاده از CURL می توان این کار را به صورت زیر انجام داد:

curl -L -H "X-Vault-Token: TOKEN" –cacert VAULT_CA
--data '{"type":"generic"}' --request POST VAULT_URL/v1/sys/mounts/SECRET_MOUNT_POINT

همه فیلدها (TOKEN، VAULT_CA، VAULT_URL، SECRET_MOUNT_POINT) با پارامترهای فایل پیکربندی مطابقت دارند. البته می‌توانید از ابزار Vault برای انجام همین کار استفاده کنید. اما به‌طور خودکار ایجاد نقطه اتصال آسان‌تر است. امیدوارم این اطلاعات برای شما مفید واقع شود و شما را در مقالات بعدی این مجموعه خواهیم دید.

رمزگذاری در MySQL: Keystore

بیشتر بخوانید:

منبع: www.habr.com

اضافه کردن نظر