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

Fix Managed Identity Cluster creation dynamic validation flow #3891

Merged
merged 5 commits into from
Oct 10, 2024
Merged
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
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,7 @@ run-rp: ci-rp podman-secrets
-e ARO_ADOPT_BY_HIVE="true" \
-e MOCK_MSI_TENANT_ID \
-e MOCK_MSI_CLIENT_ID \
-e MOCK_MSI_OBJECT_ID \
-e MOCK_MSI_CERT \
--secret aks.kubeconfig,target=/app/secrets/aks.kubeconfig \
--secret proxy-client.key,target=/app/secrets/proxy-client.key \
Expand Down
1 change: 1 addition & 0 deletions docs/deploy-development-rp.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ mock a cluster MSI. This script will also create the platform identities, platfo
- `RP_MODE`: Set to `development` to use a development RP running at
https://localhost:8443/.
- `MOCK_MSI_CLIENT_ID`: Client ID for service principal that mocks cluster MSI (see previous step).
- `MOCK_MSI_OBJECT_ID`: Object ID for service principal that mocks cluster MSI (see previous step).
- `MOCK_MSI_CERT`: Base64 encoded certificate for service principal that mocks cluster MSI (see previous step).
- `MOCK_MSI_TENANT_ID`: Tenant ID for service principal that mocks cluster MSI (see previous step).
- `PLATFORM_WORKLOAD_IDENTITY_ROLE_SETS`: The platform workload identity role sets (see previous step or value in `local_dev_env.sh`).
Expand Down
2 changes: 1 addition & 1 deletion docs/prepare-a-shared-rp-development-environment.md
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,7 @@ az ad app credential reset \
PARENT_DOMAIN_RESOURCEGROUP='$PARENT_DOMAIN_RESOURCEGROUP'
export DOMAIN_NAME="\$LOCATION.\$PARENT_DOMAIN_NAME"
export AZURE_ENVIRONMENT='AzurePublicCloud'
export OIDC_STORAGE_ACCOUNT_NAME="${RESOURCEGROUP//-}oic"
export OIDC_STORAGE_ACCOUNT_NAME="\${RESOURCEGROUP//-}oic"
EOF
```
Expand Down
1 change: 1 addition & 0 deletions env.example
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export ARO_IMAGE=arointsvc.azurecr.io/aro:latest
# out or remove them from your env file if you're only going to be creating service principal
# clusters.
export MOCK_MSI_CLIENT_ID="replace_with_value_output_by_hack/devtools/msi.sh"
export MOCK_MSI_OBJECT_ID="replace_with_value_output_by_hack/devtools/msi.sh"
export MOCK_MSI_CERT="replace_with_value_output_by_hack/devtools/msi.sh"
export MOCK_MSI_TENANT_ID="replace_with_value_output_by_hack/devtools/msi.sh"
export PLATFORM_WORKLOAD_IDENTITY_ROLE_SETS="replace_with_value_output_by_hack/devtools/msi.sh"
Expand Down
6 changes: 6 additions & 0 deletions hack/devtools/local_dev_env.sh
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,10 @@ get_mock_msi_tenantID() {
echo "$1" | jq -r .tenant
}

get_mock_msi_objectID() {
az ad sp list --all --filter "appId eq '$1'" | jq -r ".[] | .id"
}

get_mock_msi_cert() {
certFilePath=$(echo "$1" | jq -r '.fileWithCertAndPrivateKey')
base64EncodedCert=$(base64 -w 0 "$certFilePath")
Expand Down Expand Up @@ -234,6 +238,7 @@ create_miwi_env_file() {
mockClientID=$(get_mock_msi_clientID "$mockMSI")
mockTenantID=$(get_mock_msi_tenantID "$mockMSI")
mockCert=$(get_mock_msi_cert "$mockMSI")
mockObjectID=$(get_mock_msi_objectID "$mockClientID")

setup_platform_identity
cluster_msi_role_assignment "${mockClientID}"
Expand All @@ -243,6 +248,7 @@ export LOCATION=eastus
export ARO_IMAGE=arointsvc.azurecr.io/aro:latest
export RP_MODE=development # to use a development RP running at https://localhost:8443/
export MOCK_MSI_CLIENT_ID="$mockClientID"
export MOCK_MSI_OBJECT_ID="$mockObjectID"
export MOCK_MSI_TENANT_ID="$mockTenantID"
export MOCK_MSI_CERT="$mockCert"
export PLATFORM_WORKLOAD_IDENTITY_ROLE_SETS="$PLATFORM_WORKLOAD_IDENTITY_ROLE_SETS"
Expand Down
2 changes: 2 additions & 0 deletions hack/devtools/msi.sh
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,14 @@ fi
mockClientID=$(get_mock_msi_clientID "$sp")
mockTenantID=$(get_mock_msi_tenantID "$sp")
base64EncodedCert=$(get_mock_msi_cert "$sp")
mockObjectID=$(get_mock_msi_objectID "$mockClientID")

setup_platform_identity
cluster_msi_role_assignment "${mockClientID}"

# Print the extracted values
echo "Cluster MSI Client ID: $mockClientID"
echo "Cluster MSI Object ID: $mockObjectID"
echo "Cluster MSI Tenant ID: $mockTenantID"
echo "Cluster MSI Base64 Encoded Certificate: $base64EncodedCert"
echo "Platform workload identity role sets: $PLATFORM_WORKLOAD_IDENTITY_ROLE_SETS"
2 changes: 1 addition & 1 deletion pkg/cluster/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ func New(ctx context.Context, log *logrus.Entry, _env env.Interface, db database
return nil, err
}

armRoleDefinitionsClient, err := armauthorization.NewArmRoleDefinitionsClient(fpCredClusterTenant, clientOptions)
armRoleDefinitionsClient, err := armauthorization.NewArmRoleDefinitionsClient(fpCredClusterTenant, r.SubscriptionID, clientOptions)
if err != nil {
return nil, err
}
Expand Down
7 changes: 6 additions & 1 deletion pkg/cluster/deploybaseresources.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,11 +195,16 @@ func (m *manager) deployBaseResourceTemplate(ctx context.Context) error {
m.storageAccount(m.doc.OpenShiftCluster.Properties.ImageRegistryStorageAccountName, azureRegion, ocpSubnets, true),
m.storageAccountBlobContainer(m.doc.OpenShiftCluster.Properties.ImageRegistryStorageAccountName, "image-registry"),
m.clusterNSG(infraID, azureRegion),
m.clusterServicePrincipalRBAC(),
m.networkPrivateLinkService(azureRegion),
m.networkInternalLoadBalancer(azureRegion),
}

if !m.doc.OpenShiftCluster.UsesWorkloadIdentity() {
resources = append(resources,
m.clusterServicePrincipalRBAC(),
)
}

// Create a public load balancer routing if needed
if m.doc.OpenShiftCluster.Properties.NetworkProfile.OutboundType == api.OutboundTypeLoadbalancer {
m.newPublicLoadBalancer(ctx, &resources)
Expand Down
3 changes: 2 additions & 1 deletion pkg/env/prod.go
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,7 @@ func (p *prod) MsiDataplaneClientOptions(msiResourceId *arm.ResourceID) (*policy
if p.FeatureIsSet(FeatureUseMockMsiRp) {
keysToValidate := []string{
"MOCK_MSI_CLIENT_ID",
"MOCK_MSI_OBJECT_ID",
"MOCK_MSI_CERT",
"MOCK_MSI_TENANT_ID",
}
Expand All @@ -425,6 +426,7 @@ func (p *prod) MsiDataplaneClientOptions(msiResourceId *arm.ResourceID) (*policy
ClientID: ptr.To(os.Getenv("MOCK_MSI_CLIENT_ID")),
ClientSecret: ptr.To(os.Getenv("MOCK_MSI_CERT")),
TenantID: ptr.To(os.Getenv("MOCK_MSI_TENANT_ID")),
ObjectID: ptr.To(os.Getenv("MOCK_MSI_OBJECT_ID")),
ResourceID: ptr.To(msiResourceId.String()),
AuthenticationEndpoint: ptr.To(p.Environment().Cloud.ActiveDirectoryAuthorityHost),
CannotRenewAfter: &placeholder,
Expand All @@ -437,7 +439,6 @@ func (p *prod) MsiDataplaneClientOptions(msiResourceId *arm.ResourceID) (*policy
XMSAzNwperimid: []*string{&placeholder},
XMSAzTm: &placeholder,
},
ObjectID: &placeholder,
},
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package armauthorization

import (
"context"
"fmt"

"github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/arm"
Expand All @@ -17,13 +18,20 @@ type RoleDefinitionsClient interface {

type ArmRoleDefinitionsClient struct {
*armauthorization.RoleDefinitionsClient
subscriptionID string
}

var _ RoleDefinitionsClient = &ArmRoleDefinitionsClient{}

func NewArmRoleDefinitionsClient(credential azcore.TokenCredential, options *arm.ClientOptions) (*ArmRoleDefinitionsClient, error) {
func NewArmRoleDefinitionsClient(credential azcore.TokenCredential, subscriptionID string, options *arm.ClientOptions) (*ArmRoleDefinitionsClient, error) {
client, err := armauthorization.NewRoleDefinitionsClient(credential, options)
return &ArmRoleDefinitionsClient{
RoleDefinitionsClient: client,
subscriptionID: subscriptionID,
}, err
}

func (client ArmRoleDefinitionsClient) GetByID(ctx context.Context, roleDefinitionID string, options *armauthorization.RoleDefinitionsClientGetByIDOptions) (armauthorization.RoleDefinitionsClientGetByIDResponse, error) {
roleID := fmt.Sprintf("/subscriptions/%s/providers/Microsoft.Authorization/roleDefinitions/%s", client.subscriptionID, roleDefinitionID)
return client.RoleDefinitionsClient.GetByID(ctx, roleID, options)
}
4 changes: 3 additions & 1 deletion pkg/validate/dynamic/platformworkloadidentityprofile.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/Azure/ARO-RP/pkg/api"
"github.com/Azure/ARO-RP/pkg/util/azureclient/azuresdk/armauthorization"
"github.com/Azure/ARO-RP/pkg/util/rbac"
"github.com/Azure/ARO-RP/pkg/util/stringutils"
"github.com/Azure/ARO-RP/pkg/util/version"
)

Expand Down Expand Up @@ -63,7 +64,8 @@ func (dv *dynamic) ValidatePlatformWorkloadIdentityProfile(ctx context.Context,
}

for _, role := range platformWorkloadIdentityRolesByRoleName {
actions, err := getActionsForRoleDefinition(ctx, role.RoleDefinitionID, roleDefinitions)
roleDefinitionID := stringutils.LastTokenByte(role.RoleDefinitionID, '/')
actions, err := getActionsForRoleDefinition(ctx, roleDefinitionID, roleDefinitions)
if err != nil {
return err
}
Expand Down
Loading