From 4c95edd8ba140051ea256260870e31cd758a15b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wenkai=20Yin=28=E5=B0=B9=E6=96=87=E5=BC=80=29?= Date: Thu, 21 Mar 2024 15:55:29 +0800 Subject: [PATCH] Support certificate-based authentication for Azure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Support certificate-based authentication for Azure Fixes #6735 Signed-off-by: Wenkai Yin(尹文开) --- changelogs/unreleased/7549-ywk253100 | 1 + pkg/util/azure/credential.go | 21 +++++++++++++-------- pkg/util/azure/util.go | 1 + 3 files changed, 15 insertions(+), 8 deletions(-) create mode 100644 changelogs/unreleased/7549-ywk253100 diff --git a/changelogs/unreleased/7549-ywk253100 b/changelogs/unreleased/7549-ywk253100 new file mode 100644 index 000000000..898680103 --- /dev/null +++ b/changelogs/unreleased/7549-ywk253100 @@ -0,0 +1 @@ +Support certificate-based authentication for Azure \ No newline at end of file diff --git a/pkg/util/azure/credential.go b/pkg/util/azure/credential.go index 72da54b21..52df1798f 100644 --- a/pkg/util/azure/credential.go +++ b/pkg/util/azure/credential.go @@ -81,7 +81,7 @@ type configCredentialOptions struct { AdditionallyAllowedTenants []string } -// newConfigCredential works same as the azidentity.EnvironmentCredential but reads the credentials from a map +// newConfigCredential works similar as the azidentity.EnvironmentCredential but reads the credentials from a map // rather than environment variables. This is required for Velero to run B/R concurrently // https://github.com/Azure/azure-sdk-for-go/blob/sdk/azidentity/v1.3.0/sdk/azidentity/environment_credential.go#L80 func newConfigCredential(creds map[string]string, options configCredentialOptions) (azcore.TokenCredential, error) { @@ -102,19 +102,24 @@ func newConfigCredential(creds map[string]string, options configCredentialOption }) } - // certificate - if certPath := creds[CredentialKeyClientCertificatePath]; certPath != "" { - certData, err := os.ReadFile(certPath) - if err != nil { - return nil, errors.Wrapf(err, "failed to read certificate file %s", certPath) + // raw certificate or certificate file + if rawCerts, certsPath := []byte(creds[CredentialKeyClientCertificate]), creds[CredentialKeyClientCertificatePath]; len(rawCerts) > 0 || len(certsPath) > 0 { + var err error + // raw certificate isn't specified while certificate path is specified + if len(rawCerts) == 0 { + rawCerts, err = os.ReadFile(certsPath) + if err != nil { + return nil, errors.Wrapf(err, "failed to read certificate file %s", certsPath) + } } + var password []byte if v := creds[CredentialKeyClientCertificatePassword]; v != "" { password = []byte(v) } - certs, key, err := azidentity.ParseCertificates(certData, password) + certs, key, err := azidentity.ParseCertificates(rawCerts, password) if err != nil { - return nil, errors.Wrapf(err, "failed to load certificate from %s", certPath) + return nil, errors.Wrap(err, "failed to parse certificate") } o := &azidentity.ClientCertificateCredentialOptions{ AdditionallyAllowedTenants: options.AdditionallyAllowedTenants, diff --git a/pkg/util/azure/util.go b/pkg/util/azure/util.go index 41191d4b7..e708d6ce3 100644 --- a/pkg/util/azure/util.go +++ b/pkg/util/azure/util.go @@ -43,6 +43,7 @@ const ( CredentialKeyTenantID = "AZURE_TENANT_ID" // #nosec CredentialKeyClientID = "AZURE_CLIENT_ID" // #nosec CredentialKeyClientSecret = "AZURE_CLIENT_SECRET" // #nosec + CredentialKeyClientCertificate = "AZURE_CLIENT_CERTIFICATE" // #nosec CredentialKeyClientCertificatePath = "AZURE_CLIENT_CERTIFICATE_PATH" // #nosec CredentialKeyClientCertificatePassword = "AZURE_CLIENT_CERTIFICATE_PASSWORD" // #nosec CredentialKeySendCertChain = "AZURE_CLIENT_SEND_CERTIFICATE_CHAIN" // #nosec