mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2025-03-03 14:52:21 +02:00
Reload GCS credentials before renewing authentication token.
This allows the service key to be updated while a command is running. The new key should be written atomically and ideally the old key should remain valid for some period of time to avoid a race condition if the old token happens to expire at the same time that the new key is being generated.
This commit is contained in:
parent
cbafcfabf2
commit
995a8e9669
@ -15,6 +15,21 @@
|
||||
|
||||
<release-list>
|
||||
<release date="XXXX-XX-XX" version="2.48dev" title="Under Development">
|
||||
<release-core-list>
|
||||
<release-improvement-list>
|
||||
<release-item>
|
||||
<github-pull-request id="2072"/>
|
||||
|
||||
<release-item-contributor-list>
|
||||
<release-item-ideator id="daniel.farina"/>
|
||||
<release-item-contributor id="david.steele"/>
|
||||
<release-item-reviewer id="stephen.frost"/>
|
||||
</release-item-contributor-list>
|
||||
|
||||
<p>Reload GCS credentials before renewing authentication token.</p>
|
||||
</release-item>
|
||||
</release-improvement-list>
|
||||
</release-core-list>
|
||||
</release>
|
||||
|
||||
<release date="2023-07-24" version="2.47" title="Performance Improvements and Bug Fixes">
|
||||
|
@ -659,6 +659,8 @@
|
||||
<list-item><id>service</id> - Service account from locally stored key.</list-item>
|
||||
<list-item><id>token</id> - For local testing, e.g. <file>fakegcs</file>.</list-item>
|
||||
</list>
|
||||
|
||||
<p>When <br-option>repo-gcs-key-type=service</br-option> the credentials will be reloaded when the authentication token is renewed.</p>
|
||||
</text>
|
||||
|
||||
<example>auto</example>
|
||||
|
@ -89,8 +89,7 @@ struct StorageGcs
|
||||
size_t chunkSize; // Block size for resumable upload
|
||||
|
||||
StorageGcsKeyType keyType; // Auth key type
|
||||
const String *credential; // Credential (client email)
|
||||
const String *privateKey; // Private key in PEM format
|
||||
const String *key; // Key (value depends on key type)
|
||||
String *token; // Token
|
||||
time_t tokenTimeExpire; // Token expiration time (if service auth)
|
||||
HttpUrl *authUrl; // URL for authentication server
|
||||
@ -177,6 +176,13 @@ storageGcsAuthJwt(StorageGcs *this, time_t timeBegin)
|
||||
|
||||
MEM_CONTEXT_TEMP_BEGIN()
|
||||
{
|
||||
// Load client email and private key
|
||||
KeyValue *const kvKey = varKv(jsonToVar(strNewBuf(storageGetP(storageNewReadP(storagePosixNewP(FSLASH_STR), this->key)))));
|
||||
const String *const clientEmail = varStr(kvGet(kvKey, GCS_JSON_CLIENT_EMAIL_VAR));
|
||||
const String *const privateKeyRaw = varStr(kvGet(kvKey, GCS_JSON_PRIVATE_KEY_VAR));
|
||||
|
||||
CHECK(FormatError, clientEmail != NULL && privateKeyRaw != NULL, "credentials missing");
|
||||
|
||||
// Add claim
|
||||
strCatEncode(
|
||||
result, encodingBase64Url,
|
||||
@ -184,7 +190,7 @@ storageGcsAuthJwt(StorageGcs *this, time_t timeBegin)
|
||||
strNewFmt(
|
||||
"{\"iss\":\"%s\",\"scope\":\"https://www.googleapis.com/auth/devstorage.read%s\",\"aud\":\"%s\""
|
||||
",\"exp\":%" PRIu64 ",\"iat\":%" PRIu64 "}",
|
||||
strZ(this->credential), this->write ? "_write" : "_only", strZ(httpUrl(this->authUrl)),
|
||||
strZ(clientEmail), this->write ? "_write" : "_only", strZ(httpUrl(this->authUrl)),
|
||||
(uint64_t)timeBegin + 3600, (uint64_t)timeBegin)));
|
||||
|
||||
// Sign with RSA key
|
||||
@ -198,7 +204,7 @@ storageGcsAuthJwt(StorageGcs *this, time_t timeBegin)
|
||||
{
|
||||
// Load key
|
||||
bio = BIO_new(BIO_s_mem());
|
||||
BIO_write((BIO *)bio, strZ(this->privateKey), (int)strSize(this->privateKey));
|
||||
BIO_write((BIO *)bio, strZ(privateKeyRaw), (int)strSize(privateKeyRaw));
|
||||
|
||||
privateKey = PEM_read_bio_PrivateKey((BIO *)bio, NULL, NULL, NULL);
|
||||
cryptoError(privateKey == NULL, "unable to read PEM");
|
||||
@ -999,15 +1005,13 @@ storageGcsNew(
|
||||
// Read data from file for service keys
|
||||
case storageGcsKeyTypeService:
|
||||
{
|
||||
KeyValue *kvKey = varKv(jsonToVar(strNewBuf(storageGetP(storageNewReadP(storagePosixNewP(FSLASH_STR), key)))));
|
||||
this->credential = varStr(kvGet(kvKey, GCS_JSON_CLIENT_EMAIL_VAR));
|
||||
this->privateKey = varStr(kvGet(kvKey, GCS_JSON_PRIVATE_KEY_VAR));
|
||||
const KeyValue *const kvKey = varKv(
|
||||
jsonToVar(strNewBuf(storageGetP(storageNewReadP(storagePosixNewP(FSLASH_STR), key)))));
|
||||
const String *const uri = varStr(kvGet(kvKey, GCS_JSON_TOKEN_URI_VAR));
|
||||
CHECK(FormatError, uri != NULL, "uri missing");
|
||||
|
||||
CHECK(FormatError, this->credential != NULL && this->privateKey != NULL && uri != NULL, "credentials missing");
|
||||
|
||||
this->key = strDup(key);
|
||||
this->authUrl = httpUrlNewParseP(uri, .type = httpProtocolTypeHttps);
|
||||
|
||||
this->authClient = httpClientNew(
|
||||
tlsClientNewP(
|
||||
sckClientNew(httpUrlHost(this->authUrl), httpUrlPort(this->authUrl), timeout, timeout),
|
||||
|
Loading…
x
Reference in New Issue
Block a user