-
Notifications
You must be signed in to change notification settings - Fork 158
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add azure managed identity to azure package in blockstorage (#1615)
* Add utilities functions for Azure authentication + unit test to be added for utilities Signed-off-by: Le Tran <[email protected]> * Add an interface for Azure blockstorage to Authenticate credentials to be added fro authenticate Signed-off-by: Le Tran <[email protected]> * Add an option to use MSI Authorizer for Azure Signed-off-by: Le Tran <[email protected]> * Add guarding for nil + clean up comment Signed-off-by: Le Tran <[email protected]> * Update gomod and gosum files Signed-off-by: Le Tran <[email protected]> * Expose functions checking for creds Signed-off-by: Le Tran <[email protected]> * Add authenticator for client secret credentials type Signed-off-by: Le Tran <[email protected]> * Clean up according to PR reviews Signed-off-by: Le Tran <[email protected]> * Remove CredAvailibility, authentication status will be inferred from error Signed-off-by: Le Tran <[email protected]> * Address review comments Signed-off-by: Le Tran <[email protected]> * Make Azure authenticator a public interface that can be used directly Signed-off-by: Le Tran <[email protected]> Signed-off-by: Le Tran <[email protected]> Co-authored-by: Le Tran <[email protected]> Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
- Loading branch information
1 parent
6eb5736
commit 09018c8
Showing
5 changed files
with
231 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
package azure | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/Azure/go-autorest/autorest/adal" | ||
"github.com/Azure/go-autorest/autorest/azure/auth" | ||
"github.com/kanisterio/kanister/pkg/blockstorage" | ||
"github.com/pkg/errors" | ||
) | ||
|
||
// currently avaialble types: https://docs.microsoft.com/en-us/azure/developer/go/azure-sdk-authorization | ||
// to be available with azidentity: https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity#readme-credential-types | ||
// determine if the combination of creds are client secret creds | ||
func isClientCredsAvailable(config map[string]string) bool { | ||
return (config[blockstorage.AzureTenantID] != "" && | ||
config[blockstorage.AzureCientID] != "" && | ||
config[blockstorage.AzureClentSecret] != "") | ||
} | ||
|
||
// determine if the combination of creds are MSI creds | ||
func isMSICredsAvailable(config map[string]string) bool { | ||
return (config[blockstorage.AzureTenantID] == "" && | ||
config[blockstorage.AzureCientID] != "" && | ||
config[blockstorage.AzureClentSecret] == "") | ||
} | ||
|
||
// Public interface to authenticate with different Azure credentials type | ||
type AzureAuthenticator interface { | ||
Authenticate(creds map[string]string) error | ||
} | ||
|
||
func NewAzureAutheticator(config map[string]string) (AzureAuthenticator, error) { | ||
switch { | ||
case isMSICredsAvailable(config): | ||
return &msiAuthenticator{}, nil | ||
case isClientCredsAvailable(config): | ||
return &clientSecretAuthenticator{}, nil | ||
default: | ||
return nil, errors.New("Fail to get an authenticator for provided creds combination") | ||
} | ||
} | ||
|
||
// authenticate with MSI creds | ||
type msiAuthenticator struct{} | ||
|
||
func (m *msiAuthenticator) Authenticate(creds map[string]string) error { | ||
// check if MSI endpoint is available | ||
if !adal.MSIAvailable(context.Background(), nil) { | ||
return errors.New("MSI endpoint is not supported") | ||
} | ||
// create a service principal token | ||
msiConfig := auth.NewMSIConfig() | ||
msiConfig.ClientID = creds[blockstorage.AzureCientID] | ||
spt, err := msiConfig.ServicePrincipalToken() | ||
if err != nil { | ||
return errors.Wrap(err, "Failed to create a service principal token") | ||
} | ||
// network call to check for token | ||
err = spt.Refresh() | ||
if err != nil { | ||
return errors.Wrap(err, "Failed to refresh token") | ||
} | ||
// creds passed authentication | ||
return nil | ||
} | ||
|
||
// authenticate with client secret creds | ||
type clientSecretAuthenticator struct{} | ||
|
||
func (c *clientSecretAuthenticator) Authenticate(creds map[string]string) error { | ||
credConfig, err := getCredConfigForAuth(creds) | ||
if err != nil { | ||
return errors.Wrap(err, "Failed to get Client Secret config") | ||
} | ||
// create a service principal token | ||
spt, err := credConfig.ServicePrincipalToken() | ||
if err != nil { | ||
return errors.Wrap(err, "Failed to create a service principal token") | ||
} | ||
// network call to check for token | ||
err = spt.Refresh() | ||
if err != nil { | ||
return errors.Wrap(err, "Failed to refresh token") | ||
} | ||
// creds passed authentication | ||
return nil | ||
} | ||
|
||
func getCredConfigForAuth(config map[string]string) (auth.ClientCredentialsConfig, error) { | ||
tenantID, ok := config[blockstorage.AzureTenantID] | ||
if !ok { | ||
return auth.ClientCredentialsConfig{}, errors.New("Cannot get tenantID from config") | ||
} | ||
|
||
clientID, ok := config[blockstorage.AzureCientID] | ||
if !ok { | ||
return auth.ClientCredentialsConfig{}, errors.New("Cannot get clientID from config") | ||
} | ||
|
||
clientSecret, ok := config[blockstorage.AzureClentSecret] | ||
if !ok { | ||
return auth.ClientCredentialsConfig{}, errors.New("Cannot get clientSecret from config") | ||
} | ||
|
||
credConfig := auth.NewClientCredentialsConfig(clientID, clientSecret, tenantID) | ||
return credConfig, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
// Copyright 2022 The Kanister Authors. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package azure | ||
|
||
import ( | ||
"github.com/kanisterio/kanister/pkg/blockstorage" | ||
. "gopkg.in/check.v1" | ||
) | ||
|
||
type AuthSuite struct{} | ||
|
||
var _ = Suite(&AuthSuite{}) | ||
|
||
func (s *AuthSuite) SetUpSuite(c *C) { | ||
} | ||
|
||
func (s *AuthSuite) TestIsClientCredsvailable(c *C) { | ||
// success | ||
config := map[string]string{ | ||
blockstorage.AzureTenantID: "some-tenant-id", | ||
blockstorage.AzureCientID: "some-client-id", | ||
blockstorage.AzureClentSecret: "someclient-secret", | ||
} | ||
c.Assert(isClientCredsAvailable(config), Equals, true) | ||
|
||
// remove tenantID | ||
delete(config, blockstorage.AzureTenantID) | ||
c.Assert(isClientCredsAvailable(config), Equals, false) | ||
|
||
// remove client secret, only client ID left | ||
delete(config, blockstorage.AzureClentSecret) | ||
c.Assert(isClientCredsAvailable(config), Equals, false) | ||
} | ||
|
||
func (s *AuthSuite) TestIsMSICredsAvailable(c *C) { | ||
// success | ||
config := map[string]string{ | ||
blockstorage.AzureTenantID: "some-tenant-id", | ||
blockstorage.AzureCientID: "some-client-id", | ||
blockstorage.AzureClentSecret: "someclient-secret", | ||
} | ||
c.Assert(isMSICredsAvailable(config), Equals, false) | ||
|
||
// remove tenantID | ||
delete(config, blockstorage.AzureTenantID) | ||
c.Assert(isMSICredsAvailable(config), Equals, false) | ||
|
||
// remove client secret, only client ID left | ||
delete(config, blockstorage.AzureClentSecret) | ||
c.Assert(isMSICredsAvailable(config), Equals, true) | ||
} | ||
|
||
func (s *AuthSuite) TestNewAzureAutheticator(c *C) { | ||
// successful with client secret creds | ||
config := map[string]string{ | ||
blockstorage.AzureTenantID: "some-tenant-id", | ||
blockstorage.AzureCientID: "some-client-id", | ||
blockstorage.AzureClentSecret: "some-client-secret", | ||
} | ||
authenticator, err := NewAzureAutheticator(config) | ||
c.Assert(err, IsNil) | ||
_, ok := authenticator.(*clientSecretAuthenticator) | ||
c.Assert(ok, Equals, true) | ||
|
||
// successful with msi creds | ||
config = map[string]string{ | ||
blockstorage.AzureCientID: "some-client-id", | ||
} | ||
authenticator, err = NewAzureAutheticator(config) | ||
c.Assert(err, IsNil) | ||
_, ok = authenticator.(*msiAuthenticator) | ||
c.Assert(ok, Equals, true) | ||
|
||
// unsuccessful with an undefined combo of creds | ||
config = map[string]string{ | ||
blockstorage.AzureCientID: "some-client-id", | ||
blockstorage.AzureClentSecret: "some-client-secret", | ||
} | ||
authenticator, err = NewAzureAutheticator(config) | ||
c.Assert(err, NotNil) | ||
c.Assert(authenticator, IsNil) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters