Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat support for managed identity authentication in azure locking #1896

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 13 additions & 8 deletions docs/ce/azure-specific/azure-devops-locking-connection-methods.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,22 @@ There is one mandatory environment variable the user will have to set, in order

* CLIENT\_SECRET

* MANAGED\_IDENTITY

Then, depending on the value of `DIGGER_AZURE_AUTH_METHOD`, the user will have to set other environment variables.

1. **SHARED\_KEY**
* `DIGGER_AZURE_SA_NAME`: Storage account name
1. **SHARED\_KEY**
* `DIGGER_AZURE_SA_NAME`: Storage account name
* `DIGGER_AZURE_SHARED_KEY`: shared key of the storage account

2. **CONNECTION\_STRING**
2. **CONNECTION\_STRING**
* `DIGGER_AZURE_CONNECTION_STRING`: connection string

3. **CLIENT\_SECRET**
* `DIGGER_AZURE_TENANT_ID`: tenant id to use
* `DIGGER_AZURE_CLIENT_ID`: client id of the service principal
* `DIGGER_AZURE_CLIENT_SECRET`: secret of the service principal
* `DIGGER_AZURE_SA_NAME`: storage account name
3. **CLIENT\_SECRET**
* `DIGGER_AZURE_TENANT_ID`: tenant id to use
* `DIGGER_AZURE_CLIENT_ID`: client id of the service principal
* `DIGGER_AZURE_CLIENT_SECRET`: secret of the service principal
* `DIGGER_AZURE_SA_NAME`: storage account name

4. **MANAGED\_IDENTITY**
* `DIGGER_AZURE_SA_NAME`: storage account name
27 changes: 26 additions & 1 deletion libs/locking/azure/storage_account.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ type StorageAccount struct {
func NewStorageAccountLock() (*StorageAccount, error) {
authMethod := os.Getenv("DIGGER_AZURE_AUTH_METHOD")
if authMethod == "" {
return nil, fmt.Errorf("'DIGGER_AZURE_AUTH_METHOD' environment variable must be set to either 'SHARED_KEY' or 'CONNECTION_STRING' or 'CLIENT_SECRET'")
return nil, fmt.Errorf("'DIGGER_AZURE_AUTH_METHOD' environment variable must be set to either 'SHARED_KEY' or 'CONNECTION_STRING' or 'CLIENT_SECRET' or 'MANAGED_IDENTITY")
}

svcClient, err := getServiceClient(authMethod)
Expand Down Expand Up @@ -128,6 +128,10 @@ func getServiceClient(authMethod string) (*aztables.ServiceClient, error) {
return getClientSecretSvcClient()
}

if authMethod == "MANAGED_IDENTITY" {
return getManagedIdentitySvcCLient()
}

return nil, fmt.Errorf("could not initialize service client, because no valid authentication method was found")
}

Expand Down Expand Up @@ -187,6 +191,27 @@ func getClientSecretSvcClient() (*aztables.ServiceClient, error) {
return svcClient, nil
}

func getManagedIdentitySvcCLient() (*aztables.ServiceClient, error) {
saName := os.Getenv("DIGGER_AZURE_SA_NAME")

if saName == "" {
return nil, fmt.Errorf("you must set 'DIGGER_AZURE_SA_NAME' when using managed identity authentication")
}

serviceURL := getServiceURL(saName)

cred, err := azidentity.NewManagedIdentityCredential(nil)
if err != nil {
return nil, fmt.Errorf("could not create create managed identity credential: %v", err)
}

svcClient, err := aztables.NewServiceClient(serviceURL, cred, nil)
if err != nil {
return nil, fmt.Errorf("could not create service client with managed identity authentication: %v", err)
}
return svcClient, nil
}

func (sal *StorageAccount) createTableIfNotExists() error {
exists, err := sal.isTableExists(TABLE_NAME)
if err != nil {
Expand Down
26 changes: 26 additions & 0 deletions libs/locking/azure/storage_account_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,17 @@ var (
loadClientSecretEnv()
},
},
{
name: "Managed Identity authentication mode",
loadEnv: func(s *SALockTestSuite) {
// Skip this test case if we are not testing on a real storage account
if !usingRealSA {
s.T().Skip("Managed identity method can only be tested when used against a real storage account.")
return
}
loadManagedIdentityEnv()
},
},
}
)

Expand Down Expand Up @@ -137,6 +148,15 @@ func (suite *SALockTestSuite) TestNewStorageAccountLock_WithClientSecret_Missing
suite.Error(err, "should have got an error")
}

func (suite *SALockTestSuite) TestNewStorageAccountLock_WithManagedIdentity_MissingEnv() {
loadManagedIdentityEnv()
os.Setenv("DIGGER_AZURE_SA_NAME", "")

sal, err := NewStorageAccountLock()
suite.Nil(sal)
suite.Error(err, "should have got an error")
}

func (suite *SALockTestSuite) TestLock_WhenNotLockedYet() {
for _, tc := range testCases {
suite.Run(tc.name, func() {
Expand Down Expand Up @@ -373,6 +393,12 @@ func loadClientSecretEnv() {
os.Setenv("DIGGER_AZURE_SA_NAME", envs["DIGGER_AZURE_SA_NAME"])
}

func loadManagedIdentityEnv() {
os.Setenv("DIGGER_AZURE_AUTH_METHOD", "MANAGED_IDENTITY")

os.Setenv("DIGGER_AZURE_SA_NAME", envs["DIGGER_AZURE_SA_NAME"])
}

// Clean environment variables
func cleanEnv() {
for _, env := range envNames {
Expand Down