Skip to content

Commit

Permalink
chore: add design doc
Browse files Browse the repository at this point in the history
Signed-off-by: Shahram Kalantari <[email protected]>
  • Loading branch information
shahramk64 committed Nov 20, 2024
1 parent 04d1de7 commit e8a9fae
Showing 1 changed file with 165 additions and 0 deletions.
165 changes: 165 additions & 0 deletions docs/design/Refactor Azure authentication.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
# **Azure Authentication Refactoring in Ratify**

## **Introduction**
Authentication is a critical process in Ratify, ensuring secure access to artifatcs in container registries, and to keys, secrets and certificates from cloud key vaults, and other resources. Azure offers two primary SDKs for authentication in Go:

- **Azure Identity ([azidentity](https://learn.microsoft.com/en-us/azure/developer/go/azure-sdk-authentication?tabs=bash))**: Designed for seamless integration with Azure services.
- **Microsoft Authentication Library ([MSAL](https://learn.microsoft.com/en-us/entra/identity-platform/msal-overview))**: Provides advanced token management capabilities.

Currently, Ratify uses both SDKs across different components, leading to complexity and maintenance overhead. This document proposes a comprehensive refactoring of Azure authentication in Ratify to improve maintainability, reduce duplication, and streamline the user experience.

---

## **Existing Azure Authentication in Ratify**

### **ACR Token Retrieval**
Located in the **ORAS auth providers (`pkg/common/oras/authprovider/azure`)**:
1. **Azure Managed Identity (`azureidentity.go`)**:
- Uses `azidentity.NewManagedIdentityCredential` to retrieve an access token.
- Requires only the `clientID`:
```go
id := azidentity.ClientID(clientID)
opts := azidentity.ManagedIdentityCredentialOptions{ID: id}
cred, err := azidentity.NewManagedIdentityCredential(&opts)
```

2. **Azure Workload Identity (`azureworkloadidentity.go`)**:
- Uses `confidential.NewCredFromAssertionCallback` from the **MSAL** package.

### **Key Management Provider and Certificate Provider**
Both components recently replaced the deprecated `autorest` SDK with `azidentity` and now use workload identity credentials for authentication.

---

## **Challenges with the Current Design**

### 1. **Multiple SDKs**
Ratify employs both **`MSAL`** and **`azidentity`**, increasing the maintenance burden. Consolidating to a single SDK simplifies dependency management, reduces upgrade complexity, and enhances maintainability.

### 2. **Code Duplication**
Significant code duplication exists across components, particularly between Azure workload identity and managed identity implementations. Consolidating shared logic improves maintainability.

### 3. **Explicit Authentication Selection**
Currently, users must explicitly specify the authentication type. In well-defined environments like Azure Kubernetes Service (AKS), this should be inferred automatically based on environment variables.

---

## **Proposed Refactoring**

### **Goals**
1. Design a **common package** for Azure authentication logic.
2. **Infer authentication type** automatically based on the environment, reducing user configuration overhead.
3. **Unify implementations** for workload identity and managed identity in ORAS auth providers.
4. Implement a **chained authentication process**:
- Workload IdentityManaged IdentityAzure CLI.
5. Use a single SDK (**`azidentity`**) for all authentication workflows to improve maintainability and alignment with Azure best practices.

---

### **Refactoring Plan**

#### **1. Introduce a New Azure Authentication Package**
- A new package, `pkg/common/cloudauthproviders/azure`, will consolidate shared Azure authentication logic.
- Authentication will use `ChainedTokenCredential` to sequentially try:
- **Workload Identity**
- **Managed Identity**
- **Azure CLI**
- If all attempts fail, the process will return an error.

##### **Proposed Code Snippet**
```go
package azure
import (
"fmt"
"os"
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
)
func NewChainedCredential() (*azidentity.ChainedTokenCredential, error) {
var creds []azidentity.TokenCredential
// Add Workload Identity if environment variables are set
if tenantID := os.Getenv("AZURE_TENANT_ID"); tenantID != "" {
if clientID := os.Getenv("AZURE_CLIENT_ID"); clientID != "" {
if tokenFile := os.Getenv("AZURE_FEDERATED_TOKEN_FILE"); tokenFile != "" {
wiCred, err := azidentity.NewWorkloadIdentityCredential(&azidentity.WorkloadIdentityCredentialOptions{
TenantID: tenantID,
ClientID: clientID,
TokenFilePath: tokenFile,
})
if err == nil {
creds = append(creds, wiCred)
}
}
}
}
// Add Managed Identity
if clientID := os.Getenv("AZURE_CLIENT_ID"); clientID != "" {
miCred, err := azidentity.NewManagedIdentityCredential(&azidentity.ManagedIdentityCredentialOptions{
ID: azidentity.ClientID(clientID),
})
if err == nil {
creds = append(creds, miCred)
}
}
// Add Azure CLI Credential
cliCred, err := azidentity.NewAzureCLICredential(nil)
if err == nil {
creds = append(creds, cliCred)
}
if len(creds) == 0 {
return nil, fmt.Errorf("no valid credentials detected. Check environment configuration.")
}
// Combine credentials into a chain
return azidentity.NewChainedTokenCredential(creds, nil)
}
```
#### **2. Refactor ORAS Auth Providers**
- Combine `azureidentity.go` and `azureworkloadidentity.go` into a single file.
- Update the implementation to use the `pkg/common/cloudauthproviders/azure` package for authentication.
- Authentication type will be inferred based on environment variables.

#### **3. Refactor Key Management and Certificate Providers**
- Update the providers to leverage the new `pkg/common/cloudauthproviders/azure` package for authentication.
- Remove redundant logic and ensure consistent authentication processes across all providers.

---

### **Advantages of the Proposed Refactoring**

1. **Improved Maintainability**:
- A single SDK (`azidentity`) reduces dependencies and simplifies code management.
- Consolidated authentication logic minimizes duplication and enhances clarity.

2. **Enhanced User Experience**:
- Automatic detection of authentication type eliminates the need for explicit configuration in most environments.

3. **Extensibility**:
- Centralized authentication logic makes it easier to extend support for new scenarios or credential types in the future.

4. **Alignment with Azure Best Practices**:
- `azidentity` provides a Kubernetes-native experience, integrating seamlessly with other Azure SDKs.

---

### **Proposed Tasks**

1. **Create the New Azure Authentication Package**:
- Implement shared authentication logic using `azidentity` and `ChainedTokenCredential`.

2. **Refactor ORAS Auth Providers**:
- Combine `azureidentity.go` and `azureworkloadidentity.go`.
- Use the new package for authentication.

3. **Refactor Key Management and Certificate Providers**:
- Update the providers to leverage the common Azure authentication package.

4. **Test and Validate**:
- Thoroughly test the refactored components across different environments (e.g., AKS, local development) to ensure correctness and reliability.

0 comments on commit e8a9fae

Please sign in to comment.