1 /*
2 Copyright (c) 2016 MariaDB Corporation
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; version 2 of the License.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
16
17
18 #include <my_global.h>
19 #include <typelib.h>
20 #include <mysql/plugin_encryption.h>
21 #include <my_crypt.h>
22 #include <string.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <mysqld_error.h>
26 #include <my_sys.h>
27 #include <map>
28 #include <algorithm>
29 #include <string>
30 #include <vector>
31 #include <iterator>
32 #include <sstream>
33 #include <fstream>
34
35 #ifndef _WIN32
36 #include <dirent.h>
37 #endif
38
39 #include <aws/core/Aws.h>
40 #include <aws/core/client/AWSError.h>
41 #include <aws/core/utils/logging/AWSLogging.h>
42 #include <aws/core/utils/logging/ConsoleLogSystem.h>
43 #include <aws/kms/KMSClient.h>
44 #include <aws/kms/model/DecryptRequest.h>
45 #include <aws/kms/model/DecryptResult.h>
46 #include <aws/kms/model/GenerateDataKeyWithoutPlaintextRequest.h>
47 #include <aws/kms/model/GenerateDataKeyWithoutPlaintextResult.h>
48 #include <aws/core/utils/Outcome.h>
49
50 using namespace std;
51 using namespace Aws::KMS;
52 using namespace Aws::KMS::Model;
53 using namespace Aws::Utils::Logging;
54
55
56 /* Plaintext key info struct */
57 struct KEY_INFO
58 {
59 unsigned int key_id;
60 unsigned int key_version;
61 unsigned int length;
62 unsigned char data[MY_AES_MAX_KEY_LENGTH];
63 bool load_failed; /* if true, do not attempt to reload?*/
64 public:
KEY_INFOKEY_INFO65 KEY_INFO() : key_id(0), key_version(0), length(0), load_failed(false){};
66 };
67 #define KEY_ID_AND_VERSION(key_id,version) ((longlong)key_id << 32 | version)
68
69 /* Cache for the latest version, per key id */
70 static std::map<uint, uint> latest_version_cache;
71
72 /* Cache for plaintext keys */
73 static std::map<ulonglong, KEY_INFO> key_info_cache;
74
75 static const char *key_spec_names[]={ "AES_128", "AES_256", 0 };
76
77 /* Plugin variables */
78 static char* master_key_id;
79 static char* region;
80 static unsigned long key_spec;
81 static unsigned long log_level;
82 static int rotate_key;
83 static int request_timeout;
84
85 #ifndef DBUG_OFF
86 #define WITH_AWS_MOCK 1
87 #else
88 #define WITH_AWS_MOCK 0
89 #endif
90
91 #if WITH_AWS_MOCK
92 static char mock;
93 #endif
94
95
96 /* AWS functionality*/
97 static int read_and_decrypt_key(const char *path, KEY_INFO *info);
98 static int generate_and_save_datakey(uint key_id, uint version);
99
100 static int extract_id_and_version(const char *name, uint *id, uint *ver);
101 static unsigned int get_latest_key_version(unsigned int key_id);
102 static unsigned int get_latest_key_version_nolock(unsigned int key_id);
103 static int load_key(KEY_INFO *info);
104 static std::mutex mtx;
105
106
107 static Aws::KMS::KMSClient *client;
108
print_kms_error(const char * func,const Aws::Client::AWSError<Aws::KMS::KMSErrors> & err)109 static void print_kms_error(const char *func, const Aws::Client::AWSError<Aws::KMS::KMSErrors>& err)
110 {
111 my_printf_error(ER_UNKNOWN_ERROR,
112 "AWS KMS plugin : KMS Client API '%s' failed : %s - %s",
113 ME_ERROR_LOG,
114 func, err.GetExceptionName().c_str(), err.GetMessage().c_str());
115 }
116
117 #if WITH_AWS_MOCK
118 /*
119 Mock routines to test plugin without actual AWS KMS interaction
120 we only need to mock 2 functions - generating encrypted key, and decrypt
121
122 This mock functions do no-op encryption, i.e encrypt and decrypt of
123 a buffer return the buffer itself.
124 */
125
126 /*
127 Generate random "encrypted" key. We do not encrypt anything in mock mode.
128 */
mock_generate_encrypted_key(Aws::Utils::ByteBuffer * result)129 static int mock_generate_encrypted_key(Aws::Utils::ByteBuffer *result)
130 {
131 size_t len = key_spec == 0?16 : 32;
132 *result = Aws::Utils::ByteBuffer(len);
133 my_random_bytes(result->GetUnderlyingData(), (int)len);
134 return 0;
135 }
136
137
mock_decrypt(Aws::Utils::ByteBuffer input,Aws::Utils::ByteBuffer * output)138 static int mock_decrypt(Aws::Utils::ByteBuffer input, Aws::Utils::ByteBuffer* output)
139 {
140 /* We do not encrypt or decrypt in mock mode.*/
141 *output = input;
142 return 0;
143 }
144 #endif
145
146 /* Redirect AWS trace to error log */
147 class MySQLLogSystem : public Aws::Utils::Logging::FormattedLogSystem
148 {
149 public:
150
151 using Base = FormattedLogSystem;
MySQLLogSystem(LogLevel logLevel)152 MySQLLogSystem(LogLevel logLevel) :
153 Base(logLevel)
154 {
155 }
GetLogLevel(void) const156 virtual LogLevel GetLogLevel(void) const override
157 {
158 return (LogLevel)log_level;
159 }
~MySQLLogSystem()160 virtual ~MySQLLogSystem()
161 {
162 }
163
164 protected:
ProcessFormattedStatement(Aws::String && statement)165 virtual void ProcessFormattedStatement(Aws::String&& statement) override
166 {
167 #ifdef _WIN32
168 /*
169 On Windows, we can't use C runtime functions to write to stdout,
170 because we compile with static C runtime, so plugin has a stdout
171 different from server. Thus we're using WriteFile().
172 */
173 DWORD nSize= (DWORD)statement.size();
174 DWORD nWritten;
175 const char *s= statement.c_str();
176 HANDLE h= GetStdHandle(STD_OUTPUT_HANDLE);
177
178 WriteFile(h, s, nSize, &nWritten, NULL);
179 #else
180 printf("%s", statement.c_str());
181 #endif
182 }
183 };
184
185 /* Get list of files in current directory */
traverse_current_directory()186 static vector<string> traverse_current_directory()
187 {
188 vector<string> v;
189 #ifdef _WIN32
190 WIN32_FIND_DATA find_data;
191 HANDLE h= FindFirstFile("*.*", &find_data);
192 if (h == INVALID_HANDLE_VALUE)
193 return v;
194 do
195 {
196 v.push_back(find_data.cFileName);
197 }
198 while (FindNextFile(h, &find_data));
199 FindClose(h);
200 #else
201 DIR *dir = opendir(".");
202 if (!dir)
203 return v;
204 struct dirent *e;
205 while ((e= readdir(dir)))
206 v.push_back(e->d_name);
207 closedir(dir);
208 #endif
209 return v;
210 }
211
212 Aws::SDKOptions sdkOptions;
213
aws_init()214 static int aws_init()
215 {
216
217 #ifdef HAVE_YASSL
218 sdkOptions.cryptoOptions.initAndCleanupOpenSSL = true;
219 #else
220 /* Server initialized OpenSSL already, thus AWS must skip it */
221 sdkOptions.cryptoOptions.initAndCleanupOpenSSL = false;
222 #endif
223
224 Aws::InitAPI(sdkOptions);
225 InitializeAWSLogging(Aws::MakeShared<MySQLLogSystem>("aws_key_management_plugin", (Aws::Utils::Logging::LogLevel) log_level));
226
227 Aws::Client::ClientConfiguration clientConfiguration;
228 if (region && region[0])
229 {
230 clientConfiguration.region = region;
231 }
232 if (request_timeout)
233 {
234 clientConfiguration.requestTimeoutMs= request_timeout;
235 clientConfiguration.connectTimeoutMs= request_timeout;
236 }
237 client = new KMSClient(clientConfiguration);
238 if (!client)
239 {
240 my_printf_error(ER_UNKNOWN_ERROR, "Can not initialize KMS client", ME_ERROR_LOG | ME_WARNING);
241 return -1;
242 }
243 return 0;
244 }
245
init()246 static int init()
247 {
248 #if WITH_AWS_MOCK
249 if(mock)
250 return 0;
251 #endif
252 return aws_init();
253 }
254
255 /*
256 Plugin initialization.
257
258 Create KMS client and scan datadir to find out which keys and versions
259 are present.
260 */
plugin_init(void * p)261 static int plugin_init(void *p)
262 {
263 if (init())
264 return -1;
265
266 vector<string> files= traverse_current_directory();
267 for (size_t i=0; i < files.size(); i++)
268 {
269
270 KEY_INFO info;
271 if (extract_id_and_version(files[i].c_str(), &info.key_id, &info.key_version) == 0)
272 {
273 key_info_cache[KEY_ID_AND_VERSION(info.key_id, info.key_version)]= info;
274 latest_version_cache[info.key_id]= max(info.key_version, latest_version_cache[info.key_id]);
275 }
276 }
277 return 0;
278 }
279
280
aws_shutdown()281 static void aws_shutdown()
282 {
283 delete client;
284 ShutdownAWSLogging();
285 Aws::ShutdownAPI(sdkOptions);
286 }
287
288
shutdown()289 static void shutdown()
290 {
291 #if WITH_AWS_MOCK
292 if(mock)
293 return;
294 #endif
295 aws_shutdown();
296 }
297
298
plugin_deinit(void * p)299 static int plugin_deinit(void *p)
300 {
301 latest_version_cache.clear();
302 key_info_cache.clear();
303 shutdown();
304 return 0;
305 }
306
307 /* Generate filename to store the ciphered key */
format_keyfile_name(char * buf,size_t size,uint key_id,uint version)308 static void format_keyfile_name(char *buf, size_t size, uint key_id, uint version)
309 {
310 snprintf(buf, size, "aws-kms-key.%u.%u", key_id, version);
311 }
312
313 /* Extract key id and version from file name */
extract_id_and_version(const char * name,uint * id,uint * ver)314 static int extract_id_and_version(const char *name, uint *id, uint *ver)
315 {
316 int len;
317 int n= sscanf(name, "aws-kms-key.%u.%u%n", id, ver, &len);
318 if (n == 2 && *id > 0 && *ver > 0 && len == (int)strlen(name))
319 return 0;
320 return 1;
321 }
322
323 /*
324 Decrypt key stored in aws-kms-key.<id>.<version>
325 Cache the decrypted key.
326 */
load_key(KEY_INFO * info)327 static int load_key(KEY_INFO *info)
328 {
329 int ret;
330 char path[256];
331
332 format_keyfile_name(path, sizeof(path), info->key_id, info->key_version);
333 ret= read_and_decrypt_key(path, info);
334 if (ret)
335 info->load_failed= true;
336
337 latest_version_cache[info->key_id]= max(latest_version_cache[info->key_id], info->key_version);
338 key_info_cache[KEY_ID_AND_VERSION(info->key_id, info->key_version)]= *info;
339
340 if (!ret)
341 {
342 my_printf_error(ER_UNKNOWN_ERROR, "AWS KMS plugin: loaded key %u, version %u, key length %u bit", ME_ERROR_LOG | ME_NOTE,
343 info->key_id, info->key_version,(uint)info->length*8);
344 }
345 else
346 {
347 my_printf_error(ER_UNKNOWN_ERROR, "AWS KMS plugin: key %u, version %u could not be decrypted", ME_ERROR_LOG | ME_WARNING,
348 info->key_id, info->key_version);
349 }
350 return ret;
351 }
352
353
354 /*
355 Get latest version for the key.
356
357 If key is not decrypted yet, this function also decrypt the key
358 and error will be returned if decryption fails.
359
360 The reason for that is that Innodb crashes
361 in case errors are returned by get_key(),
362
363 A new key will be created if it does not exist, provided there is
364 valid master_key_id.
365 */
get_latest_key_version(unsigned int key_id)366 static unsigned int get_latest_key_version(unsigned int key_id)
367 {
368 unsigned int ret;
369 mtx.lock();
370 ret= get_latest_key_version_nolock(key_id);
371 mtx.unlock();
372 return ret;
373 }
374
get_latest_key_version_nolock(unsigned int key_id)375 static unsigned int get_latest_key_version_nolock(unsigned int key_id)
376 {
377 KEY_INFO info;
378 uint ver;
379
380 ver= latest_version_cache[key_id];
381 if (ver > 0)
382 {
383 info= key_info_cache[KEY_ID_AND_VERSION(key_id, ver)];
384 }
385 if (info.load_failed)
386 {
387 /* Decryption failed previously, don't retry */
388 return(ENCRYPTION_KEY_VERSION_INVALID);
389 }
390 else if (ver > 0)
391 {
392 /* Key exists already, return it*/
393 if (info.length > 0)
394 return(ver);
395 }
396 else // (ver == 0)
397 {
398 /* Generate a new key, version 1 */
399 if (generate_and_save_datakey(key_id, 1) != 0)
400 return(ENCRYPTION_KEY_VERSION_INVALID);
401 info.key_id= key_id;
402 info.key_version= 1;
403 info.length= 0;
404 }
405
406 if (load_key(&info))
407 return(ENCRYPTION_KEY_VERSION_INVALID);
408 return(info.key_version);
409 }
410
411 /* Decrypt Byte buffer with AWS. */
aws_decrypt(Aws::Utils::ByteBuffer input,Aws::Utils::ByteBuffer * output)412 static int aws_decrypt(Aws::Utils::ByteBuffer input, Aws::Utils::ByteBuffer* output)
413 {
414 DecryptRequest request;
415 request.SetCiphertextBlob(input);
416 DecryptOutcome outcome = client->Decrypt(request);
417 if (!outcome.IsSuccess())
418 {
419 print_kms_error("Decrypt", outcome.GetError());
420 return -1;
421 }
422 *output= outcome.GetResult().GetPlaintext();
423 return 0;
424 }
425
426
decrypt(Aws::Utils::ByteBuffer input,Aws::Utils::ByteBuffer * output)427 static int decrypt(Aws::Utils::ByteBuffer input, Aws::Utils::ByteBuffer* output)
428 {
429 #if WITH_AWS_MOCK
430 if(mock)
431 return mock_decrypt(input,output);
432 #endif
433 return aws_decrypt(input, output);
434 }
435
436 /*
437 Decrypt a file with KMS
438 */
read_and_decrypt_key(const char * path,KEY_INFO * info)439 static int read_and_decrypt_key(const char *path, KEY_INFO *info)
440 {
441
442 /* Read file content into memory */
443 ifstream ifs(path, ios::binary | ios::ate);
444 if (!ifs.good())
445 {
446 my_printf_error(ER_UNKNOWN_ERROR, "can't open file %s", ME_ERROR_LOG, path);
447 return(-1);
448 }
449 size_t pos = (size_t)ifs.tellg();
450 if (!pos || pos == SIZE_T_MAX)
451 {
452 my_printf_error(ER_UNKNOWN_ERROR, "invalid key file %s", ME_ERROR_LOG, path);
453 return(-1);
454 }
455 std::vector<char> contents(pos);
456 ifs.seekg(0, ios::beg);
457 ifs.read(&contents[0], pos);
458
459 /* Decrypt data the with AWS */
460
461 Aws::Utils::ByteBuffer input((unsigned char *)contents.data(), pos);
462 Aws::Utils::ByteBuffer plaintext;
463
464 if (decrypt(input, &plaintext))
465 {
466 return -1;
467 }
468
469 size_t len = plaintext.GetLength();
470
471 if (len > sizeof(info->data))
472 {
473 my_printf_error(ER_UNKNOWN_ERROR, "AWS KMS plugin: encoding key too large for %s", ME_ERROR_LOG, path);
474 return(ENCRYPTION_KEY_BUFFER_TOO_SMALL);
475 }
476 memcpy(info->data, plaintext.GetUnderlyingData(), len);
477 info->length= (unsigned int)len;
478 return(0);
479 }
480
481
aws_generate_encrypted_key(Aws::Utils::ByteBuffer * result)482 int aws_generate_encrypted_key(Aws::Utils::ByteBuffer *result)
483 {
484 if (!master_key_id[0])
485 {
486 my_printf_error(ER_UNKNOWN_ERROR,
487 "Can't generate encryption key, because 'aws_key_management_master_key_id' parameter is not set",
488 MYF(0));
489 return(-1);
490 }
491 GenerateDataKeyWithoutPlaintextRequest request;
492 request.SetKeyId(master_key_id);
493 request.SetKeySpec(DataKeySpecMapper::GetDataKeySpecForName(key_spec_names[key_spec]));
494
495 GenerateDataKeyWithoutPlaintextOutcome outcome;
496 outcome= client->GenerateDataKeyWithoutPlaintext(request);
497 if (!outcome.IsSuccess())
498 {
499 print_kms_error("GenerateDataKeyWithoutPlaintext", outcome.GetError());
500 return(-1);
501 }
502 *result = outcome.GetResult().GetCiphertextBlob();
503 return 0;
504 }
505
506
generate_encrypted_key(Aws::Utils::ByteBuffer * output)507 static int generate_encrypted_key(Aws::Utils::ByteBuffer *output)
508 {
509 #if WITH_AWS_MOCK
510 if(mock)
511 return mock_generate_encrypted_key(output);
512 #endif
513 return aws_generate_encrypted_key(output);
514 }
515
516 /* Generate a new datakey and store it a file */
generate_and_save_datakey(uint keyid,uint version)517 static int generate_and_save_datakey(uint keyid, uint version)
518 {
519 Aws::Utils::ByteBuffer byteBuffer;
520
521 if (generate_encrypted_key(&byteBuffer))
522 return -1;
523
524 string out;
525 char filename[20];
526 format_keyfile_name(filename, sizeof(filename), keyid, version);
527 int fd= open(filename, O_WRONLY |O_CREAT|O_BINARY, IF_WIN(_S_IREAD, S_IRUSR| S_IRGRP| S_IROTH));
528 if (fd < 0)
529 {
530 my_printf_error(ER_UNKNOWN_ERROR, "AWS KMS plugin: Can't create file %s", ME_ERROR_LOG, filename);
531 return(-1);
532 }
533 unsigned int len= (unsigned int)byteBuffer.GetLength();
534 if (write(fd, byteBuffer.GetUnderlyingData(), len) != len)
535 {
536 my_printf_error(ER_UNKNOWN_ERROR, "AWS KMS plugin: can't write to %s", ME_ERROR_LOG, filename);
537 close(fd);
538 unlink(filename);
539 return(-1);
540 }
541 close(fd);
542 my_printf_error(ER_UNKNOWN_ERROR, "AWS KMS plugin: generated encrypted datakey for key id=%u, version=%u", ME_ERROR_LOG | ME_NOTE,
543 keyid, version);
544 return(0);
545 }
546
547 /* Key rotation for a single key */
rotate_single_key(uint key_id)548 static int rotate_single_key(uint key_id)
549 {
550 uint ver;
551 ver= latest_version_cache[key_id];
552
553 if (!ver)
554 {
555 my_printf_error(ER_UNKNOWN_ERROR, "key %u does not exist", MYF(ME_JUST_WARNING), key_id);
556 return -1;
557 }
558 else if (generate_and_save_datakey(key_id, ver + 1))
559 {
560 my_printf_error(ER_UNKNOWN_ERROR, "Could not generate datakey for key id= %u, ver= %u",
561 MYF(ME_JUST_WARNING), key_id, ver);
562 return -1;
563 }
564 else
565 {
566 KEY_INFO info;
567 info.key_id= key_id;
568 info.key_version = ver + 1;
569 if (load_key(&info))
570 {
571 my_printf_error(ER_UNKNOWN_ERROR, "Could not load datakey for key id= %u, ver= %u",
572 MYF(ME_JUST_WARNING), key_id, ver);
573 return -1;
574 }
575 }
576 return 0;
577 }
578
579 /* Key rotation for all key ids */
rotate_all_keys()580 static int rotate_all_keys()
581 {
582 int ret= 0;
583 for (map<uint, uint>::iterator it= latest_version_cache.begin(); it != latest_version_cache.end(); it++)
584 {
585 ret= rotate_single_key(it->first);
586 if (ret)
587 break;
588 }
589 return ret;
590 }
591
update_rotate(MYSQL_THD,struct st_mysql_sys_var *,void *,const void * val)592 static void update_rotate(MYSQL_THD, struct st_mysql_sys_var *, void *, const void *val)
593 {
594 if (!master_key_id[0])
595 {
596 my_printf_error(ER_UNKNOWN_ERROR,
597 "aws_key_management_master_key_id must be set to generate new data keys", MYF(ME_JUST_WARNING));
598 return;
599 }
600 mtx.lock();
601 rotate_key= *(int *)val;
602 switch (rotate_key)
603 {
604 case 0:
605 break;
606 case -1:
607 rotate_all_keys();
608 break;
609 default:
610 rotate_single_key(rotate_key);
611 break;
612 }
613 rotate_key= 0;
614 mtx.unlock();
615 }
616
get_key(unsigned int key_id,unsigned int version,unsigned char * dstbuf,unsigned int * buflen)617 static unsigned int get_key(
618 unsigned int key_id,
619 unsigned int version,
620 unsigned char* dstbuf,
621 unsigned int* buflen)
622 {
623 KEY_INFO info;
624
625 mtx.lock();
626 info= key_info_cache[KEY_ID_AND_VERSION(key_id, version)];
627 if (info.length == 0 && !info.load_failed)
628 {
629 info.key_id= key_id;
630 info.key_version= version;
631 load_key(&info);
632 }
633 mtx.unlock();
634 if (info.load_failed)
635 return(ENCRYPTION_KEY_VERSION_INVALID);
636 if (*buflen < info.length)
637 {
638 *buflen= info.length;
639 return(ENCRYPTION_KEY_BUFFER_TOO_SMALL);
640 }
641 *buflen= info.length;
642 memcpy(dstbuf, info.data, info.length);
643 return(0);
644 }
645
646
647 /* Plugin defs */
648 struct st_mariadb_encryption aws_key_management_plugin= {
649 MariaDB_ENCRYPTION_INTERFACE_VERSION,
650 get_latest_key_version,
651 get_key,
652 // use default encrypt/decrypt functions
653 0, 0, 0, 0, 0
654 };
655
656
657 static TYPELIB key_spec_typelib =
658 {
659 array_elements(key_spec_names) - 1, "",
660 key_spec_names, NULL
661 };
662
663 const char *log_level_names[] =
664 {
665 "Off",
666 "Fatal",
667 "Error",
668 "Warn",
669 "Info",
670 "Debug",
671 "Trace",
672 0
673 };
674
675 static TYPELIB log_level_typelib =
676 {
677 array_elements(log_level_names) - 1, "",
678 log_level_names, NULL
679 };
680
681 static MYSQL_SYSVAR_STR(master_key_id, master_key_id,
682 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC,
683 "Key id for master encryption key. Used to create new datakeys. If not set, no new keys will be created",
684 NULL, NULL, "");
685
686 static MYSQL_SYSVAR_ENUM(key_spec, key_spec,
687 PLUGIN_VAR_RQCMDARG,
688 "Encryption algorithm used to create new keys.",
689 NULL, NULL, 0, &key_spec_typelib);
690
691
692 static MYSQL_SYSVAR_ENUM(log_level, log_level,
693 PLUGIN_VAR_RQCMDARG,
694 "Logging for AWS API",
695 NULL, NULL, 0, &log_level_typelib);
696
697
698 static MYSQL_SYSVAR_INT(rotate_key, rotate_key,
699 PLUGIN_VAR_RQCMDARG,
700 "Set this variable to key id to perform rotation of the key. Specify -1 to rotate all keys",
701 NULL, update_rotate, 0, -1, INT_MAX, 1);
702
703
704 static MYSQL_SYSVAR_INT(request_timeout, request_timeout,
705 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
706 "Timeout in milliseconds for create HTTPS connection or execute AWS request. Specify 0 to use SDK default.",
707 NULL, NULL, 0, 0, INT_MAX, 1);
708
709 static MYSQL_SYSVAR_STR(region, region,
710 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
711 "AWS region. For example us-east-1, or eu-central-1. If no value provided, SDK default is used.",
712 NULL, NULL, "");
713
714 #if WITH_AWS_MOCK
715 static MYSQL_SYSVAR_BOOL(mock, mock,
716 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
717 "Mock AWS KMS calls (for testing).",
718 NULL, NULL, 0);
719 #endif
720
721 static struct st_mysql_sys_var* settings[]= {
722 MYSQL_SYSVAR(master_key_id),
723 MYSQL_SYSVAR(key_spec),
724 MYSQL_SYSVAR(rotate_key),
725 MYSQL_SYSVAR(log_level),
726 MYSQL_SYSVAR(request_timeout),
727 MYSQL_SYSVAR(region),
728 #if WITH_AWS_MOCK
729 MYSQL_SYSVAR(mock),
730 #endif
731 NULL
732 };
733
734 /*
735 Plugin library descriptor
736 */
maria_declare_plugin(aws_key_management)737 maria_declare_plugin(aws_key_management)
738 {
739 MariaDB_ENCRYPTION_PLUGIN,
740 &aws_key_management_plugin,
741 "aws_key_management",
742 "MariaDB Corporation",
743 "AWS key management plugin",
744 PLUGIN_LICENSE_GPL,
745 plugin_init,
746 plugin_deinit,
747 0x0100,
748 NULL,
749 settings,
750 "1.0",
751 MariaDB_PLUGIN_MATURITY_STABLE
752 }
753 maria_declare_plugin_end;
754