зеркало из https://github.com/Azure/ARO-RP.git
Merge pull request #3957 from Azure/niontive/ARO-6297
Support MSI in canary
This commit is contained in:
Коммит
0e78969cec
2
go.mod
2
go.mod
|
@ -23,7 +23,7 @@ require (
|
|||
github.com/Azure/go-autorest/autorest/to v0.4.0
|
||||
github.com/Azure/go-autorest/autorest/validation v0.3.1
|
||||
github.com/Azure/go-autorest/tracing v0.6.0
|
||||
github.com/Azure/msi-dataplane v0.0.6
|
||||
github.com/Azure/msi-dataplane v0.0.8
|
||||
github.com/apparentlymart/go-cidr v1.1.0
|
||||
github.com/codahale/etm v0.0.0-20141003032925-c00c9e6fb4c9
|
||||
github.com/containers/image/v5 v5.30.1
|
||||
|
|
4
go.sum
4
go.sum
|
@ -66,8 +66,8 @@ github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+Z
|
|||
github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
|
||||
github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo=
|
||||
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
|
||||
github.com/Azure/msi-dataplane v0.0.6 h1:+IhGETRF9lLNlbs6793xWFKMcbborBtaR2ops1XWlPo=
|
||||
github.com/Azure/msi-dataplane v0.0.6/go.mod h1:/fXvAsxSogxoT7If0xfaeyaIQ7Q/0xAY9ISn7lOpA4o=
|
||||
github.com/Azure/msi-dataplane v0.0.8 h1:vIopp85cLy1kWdZUaMnNlu1ssvdRLOxU8KRdTahWrwg=
|
||||
github.com/Azure/msi-dataplane v0.0.8/go.mod h1:/fXvAsxSogxoT7If0xfaeyaIQ7Q/0xAY9ISn7lOpA4o=
|
||||
github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM=
|
||||
github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU=
|
||||
|
|
|
@ -149,7 +149,7 @@ func New(ctx context.Context, log *logrus.Entry, _env env.Interface, db database
|
|||
return nil, err
|
||||
}
|
||||
|
||||
localFPAuthorizer, err := _env.FPAuthorizer(_env.TenantID(), _env.Environment().ResourceManagerScope)
|
||||
localFPAuthorizer, err := _env.FPAuthorizer(_env.TenantID(), nil, _env.Environment().ResourceManagerScope)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -160,7 +160,7 @@ func New(ctx context.Context, log *logrus.Entry, _env env.Interface, db database
|
|||
return nil, err
|
||||
}
|
||||
|
||||
fpCredClusterTenant, err := _env.FPNewClientCertificateCredential(subscriptionDoc.Subscription.Properties.TenantID)
|
||||
fpCredClusterTenant, err := _env.FPNewClientCertificateCredential(subscriptionDoc.Subscription.Properties.TenantID, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -175,7 +175,7 @@ func New(ctx context.Context, log *logrus.Entry, _env env.Interface, db database
|
|||
}
|
||||
fpspID := tokenClaims.ObjectId
|
||||
|
||||
fpCredRPTenant, err := _env.FPNewClientCertificateCredential(_env.TenantID())
|
||||
fpCredRPTenant, err := _env.FPNewClientCertificateCredential(_env.TenantID(), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -325,7 +325,12 @@ func New(ctx context.Context, log *logrus.Entry, _env env.Interface, db database
|
|||
return nil, err
|
||||
}
|
||||
|
||||
authenticatorPolicy := dataplane.NewAuthenticatorPolicy(fpCredRPTenant, _env.MsiRpEndpoint())
|
||||
// MSI dataplane client receives tenant from the bearer challenge, so we can't limit the allowed tenants in the credential
|
||||
fpMSICred, err := _env.FPNewClientCertificateCredential(_env.TenantID(), []string{"*"})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
authenticatorPolicy := dataplane.NewAuthenticatorPolicy(fpMSICred, _env.MsiRpEndpoint())
|
||||
msiDataplane, err := dataplane.NewClient(cloud, authenticatorPolicy, msiDataplaneClientOptions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -79,7 +79,7 @@ func newARMHelper(ctx context.Context, log *logrus.Entry, env Interface) (ARMHel
|
|||
return nil, err
|
||||
}
|
||||
|
||||
options := env.Environment().ClientCertificateCredentialOptions()
|
||||
options := env.Environment().ClientCertificateCredentialOptions(nil)
|
||||
armHelperTokenCredential, err := azidentity.NewClientCertificateCredential(env.TenantID(), os.Getenv("AZURE_ARM_CLIENT_ID"), certs, key, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -89,7 +89,7 @@ func newARMHelper(ctx context.Context, log *logrus.Entry, env Interface) (ARMHel
|
|||
armHelperAuthorizer := azidext.NewTokenCredentialAdapter(armHelperTokenCredential, scopes)
|
||||
|
||||
// Graph service client uses the first party service principal.
|
||||
fpTokenCredential, err := env.FPNewClientCertificateCredential(env.TenantID())
|
||||
fpTokenCredential, err := env.FPNewClientCertificateCredential(env.TenantID(), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -81,8 +81,8 @@ func (d *dev) Listen() (net.Listener, error) {
|
|||
}
|
||||
|
||||
// TODO: Delete FPAuthorizer once the replace from track1 to track2 is done.
|
||||
func (d *dev) FPAuthorizer(tenantID string, scopes ...string) (autorest.Authorizer, error) {
|
||||
fpTokenCredential, err := d.FPNewClientCertificateCredential(tenantID)
|
||||
func (d *dev) FPAuthorizer(tenantID string, additionalTenants []string, scopes ...string) (autorest.Authorizer, error) {
|
||||
fpTokenCredential, err := d.FPNewClientCertificateCredential(tenantID, additionalTenants)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -90,10 +90,10 @@ func (d *dev) FPAuthorizer(tenantID string, scopes ...string) (autorest.Authoriz
|
|||
return azidext.NewTokenCredentialAdapter(fpTokenCredential, scopes), nil
|
||||
}
|
||||
|
||||
func (d *dev) FPNewClientCertificateCredential(tenantID string) (*azidentity.ClientCertificateCredential, error) {
|
||||
func (d *dev) FPNewClientCertificateCredential(tenantID string, additionalTenants []string) (*azidentity.ClientCertificateCredential, error) {
|
||||
fpPrivateKey, fpCertificates := d.fpCertificateRefresher.GetCertificates()
|
||||
|
||||
options := d.Environment().ClientCertificateCredentialOptions()
|
||||
options := d.Environment().ClientCertificateCredentialOptions(additionalTenants)
|
||||
credential, err := azidentity.NewClientCertificateCredential(tenantID, d.fpClientID, fpCertificates, fpPrivateKey, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -89,8 +89,8 @@ type Interface interface {
|
|||
Domain() string
|
||||
FeatureIsSet(Feature) bool
|
||||
// TODO: Delete FPAuthorizer once the replace from track1 to track2 is done.
|
||||
FPAuthorizer(string, ...string) (autorest.Authorizer, error)
|
||||
FPNewClientCertificateCredential(string) (*azidentity.ClientCertificateCredential, error)
|
||||
FPAuthorizer(string, []string, ...string) (autorest.Authorizer, error)
|
||||
FPNewClientCertificateCredential(string, []string) (*azidentity.ClientCertificateCredential, error)
|
||||
FPClientID() string
|
||||
Listen() (net.Listener, error)
|
||||
GatewayDomains() []string
|
||||
|
|
|
@ -160,7 +160,7 @@ func newProd(ctx context.Context, log *logrus.Entry, component ServiceComponent)
|
|||
return nil, err
|
||||
}
|
||||
|
||||
localFPKVAuthorizer, err := p.FPAuthorizer(p.TenantID(), p.Environment().KeyVaultScope)
|
||||
localFPKVAuthorizer, err := p.FPAuthorizer(p.TenantID(), nil, p.Environment().KeyVaultScope)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -338,8 +338,8 @@ func (p *prod) FeatureIsSet(f Feature) bool {
|
|||
}
|
||||
|
||||
// TODO: Delete FPAuthorizer once the replace from track1 to track2 is done.
|
||||
func (p *prod) FPAuthorizer(tenantID string, scopes ...string) (autorest.Authorizer, error) {
|
||||
fpTokenCredential, err := p.FPNewClientCertificateCredential(tenantID)
|
||||
func (p *prod) FPAuthorizer(tenantID string, additionalTenants []string, scopes ...string) (autorest.Authorizer, error) {
|
||||
fpTokenCredential, err := p.FPNewClientCertificateCredential(tenantID, additionalTenants)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -383,10 +383,10 @@ func (p *prod) LiveConfig() liveconfig.Manager {
|
|||
return p.liveConfig
|
||||
}
|
||||
|
||||
func (p *prod) FPNewClientCertificateCredential(tenantID string) (*azidentity.ClientCertificateCredential, error) {
|
||||
func (p *prod) FPNewClientCertificateCredential(tenantID string, additionalTenants []string) (*azidentity.ClientCertificateCredential, error) {
|
||||
fpPrivateKey, fpCertificates := p.fpCertificateRefresher.GetCertificates()
|
||||
|
||||
options := p.Environment().ClientCertificateCredentialOptions()
|
||||
options := p.Environment().ClientCertificateCredentialOptions(additionalTenants)
|
||||
credential, err := azidentity.NewClientCertificateCredential(tenantID, p.fpClientID, fpCertificates, fpPrivateKey, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -29,7 +29,7 @@ type appLensActions struct {
|
|||
|
||||
func NewAppLensActions(log *logrus.Entry, env env.Interface, oc *api.OpenShiftCluster,
|
||||
subscriptionDoc *api.SubscriptionDocument) (AppLensActions, error) {
|
||||
fpClientCertCred, err := env.FPNewClientCertificateCredential(env.Environment().AppLensTenantID)
|
||||
fpClientCertCred, err := env.FPNewClientCertificateCredential(env.Environment().AppLensTenantID, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ type azureActions struct {
|
|||
// NewAzureActions returns an azureActions
|
||||
func NewAzureActions(log *logrus.Entry, env env.Interface, oc *api.OpenShiftCluster,
|
||||
subscriptionDoc *api.SubscriptionDocument) (AzureActions, error) {
|
||||
fpAuth, err := env.FPAuthorizer(subscriptionDoc.Subscription.Properties.TenantID,
|
||||
fpAuth, err := env.FPAuthorizer(subscriptionDoc.Subscription.Properties.TenantID, nil,
|
||||
env.Environment().ResourceManagerScope)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -29,7 +29,7 @@ var requiredResourceProviders = []string{
|
|||
}
|
||||
|
||||
func (p providersValidator) ValidateProviders(ctx context.Context, azEnv *azureclient.AROEnvironment, environment env.Interface, subscriptionID, tenantID string) error {
|
||||
fpAuthorizer, err := environment.FPAuthorizer(tenantID, environment.Environment().ResourceManagerScope)
|
||||
fpAuthorizer, err := environment.FPAuthorizer(tenantID, nil, environment.Environment().ResourceManagerScope)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ func addRequiredResources(requiredResources map[string]int, vmSize api.VMSize, c
|
|||
// creation
|
||||
// It is a method on struct so we can make use of interfaces.
|
||||
func (q quotaValidator) ValidateQuota(ctx context.Context, azEnv *azureclient.AROEnvironment, environment env.Interface, subscriptionID, tenantID string, oc *api.OpenShiftCluster) error {
|
||||
fpAuthorizer, err := environment.FPAuthorizer(tenantID, environment.Environment().ResourceManagerScope)
|
||||
fpAuthorizer, err := environment.FPAuthorizer(tenantID, nil, environment.Environment().ResourceManagerScope)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ type SkuValidator interface {
|
|||
type skuValidator struct{}
|
||||
|
||||
func (s skuValidator) ValidateVMSku(ctx context.Context, azEnv *azureclient.AROEnvironment, environment env.Interface, subscriptionID, tenantID string, oc *api.OpenShiftCluster) error {
|
||||
fpAuthorizer, err := environment.FPAuthorizer(tenantID, environment.Environment().ResourceManagerScope)
|
||||
fpAuthorizer, err := environment.FPAuthorizer(tenantID, nil, environment.Environment().ResourceManagerScope)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -68,7 +68,7 @@ func NewMonitor(log *logrus.Entry, oc *api.OpenShiftCluster, e env.Interface, su
|
|||
return &monitoring.NoOpMonitor{Wg: wg}
|
||||
}
|
||||
|
||||
token, err := e.FPNewClientCertificateCredential(tenantID)
|
||||
token, err := e.FPNewClientCertificateCredential(tenantID, nil)
|
||||
if err != nil {
|
||||
log.Error("Unable to create FP Authorizer for NSG monitoring.", err)
|
||||
emitter.EmitGauge(MetricFailedNSGMonitorCreation, int64(1), dims)
|
||||
|
|
|
@ -613,7 +613,7 @@ func TestNewMonitor(t *testing.T) {
|
|||
emitter.EXPECT().EmitGauge(MetricFailedNSGMonitorCreation, int64(1), dims)
|
||||
},
|
||||
mockInterface: func(mi *mock_env.MockInterface) {
|
||||
mi.EXPECT().FPNewClientCertificateCredential(gomock.Any()).Return(nil, errors.New("Unknown Error"))
|
||||
mi.EXPECT().FPNewClientCertificateCredential(gomock.Any(), gomock.Any()).Return(nil, errors.New("Unknown Error"))
|
||||
},
|
||||
tick: true,
|
||||
valid: isOfType[*monitoring.NoOpMonitor],
|
||||
|
@ -627,7 +627,7 @@ func TestNewMonitor(t *testing.T) {
|
|||
emitter.EXPECT().EmitGauge(MetricPreconfiguredNSGEnabled, int64(1), dims)
|
||||
},
|
||||
mockInterface: func(mi *mock_env.MockInterface) {
|
||||
mi.EXPECT().FPNewClientCertificateCredential(gomock.Any()).Return(&azidentity.ClientCertificateCredential{}, nil)
|
||||
mi.EXPECT().FPNewClientCertificateCredential(gomock.Any(), gomock.Any()).Return(&azidentity.ClientCertificateCredential{}, nil)
|
||||
mi.EXPECT().Environment().Return(&azureclient.AROEnvironment{})
|
||||
},
|
||||
tick: true,
|
||||
|
|
|
@ -121,8 +121,9 @@ func (e *AROEnvironment) ArmClientOptions() *arm.ClientOptions {
|
|||
}
|
||||
}
|
||||
|
||||
func (e *AROEnvironment) ClientCertificateCredentialOptions() *azidentity.ClientCertificateCredentialOptions {
|
||||
func (e *AROEnvironment) ClientCertificateCredentialOptions(additionalTenants []string) *azidentity.ClientCertificateCredentialOptions {
|
||||
return &azidentity.ClientCertificateCredentialOptions{
|
||||
AdditionallyAllowedTenants: additionalTenants,
|
||||
ClientOptions: azcore.ClientOptions{
|
||||
Cloud: e.Cloud,
|
||||
},
|
||||
|
|
|
@ -296,10 +296,10 @@ func (mr *MockInterfaceMockRecorder) Environment() *gomock.Call {
|
|||
}
|
||||
|
||||
// FPAuthorizer mocks base method.
|
||||
func (m *MockInterface) FPAuthorizer(arg0 string, arg1 ...string) (autorest.Authorizer, error) {
|
||||
func (m *MockInterface) FPAuthorizer(arg0 string, arg1 []string, arg2 ...string) (autorest.Authorizer, error) {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []any{arg0}
|
||||
for _, a := range arg1 {
|
||||
varargs := []any{arg0, arg1}
|
||||
for _, a := range arg2 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "FPAuthorizer", varargs...)
|
||||
|
@ -309,9 +309,9 @@ func (m *MockInterface) FPAuthorizer(arg0 string, arg1 ...string) (autorest.Auth
|
|||
}
|
||||
|
||||
// FPAuthorizer indicates an expected call of FPAuthorizer.
|
||||
func (mr *MockInterfaceMockRecorder) FPAuthorizer(arg0 any, arg1 ...any) *gomock.Call {
|
||||
func (mr *MockInterfaceMockRecorder) FPAuthorizer(arg0, arg1 any, arg2 ...any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
varargs := append([]any{arg0}, arg1...)
|
||||
varargs := append([]any{arg0, arg1}, arg2...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FPAuthorizer", reflect.TypeOf((*MockInterface)(nil).FPAuthorizer), varargs...)
|
||||
}
|
||||
|
||||
|
@ -330,18 +330,18 @@ func (mr *MockInterfaceMockRecorder) FPClientID() *gomock.Call {
|
|||
}
|
||||
|
||||
// FPNewClientCertificateCredential mocks base method.
|
||||
func (m *MockInterface) FPNewClientCertificateCredential(arg0 string) (*azidentity.ClientCertificateCredential, error) {
|
||||
func (m *MockInterface) FPNewClientCertificateCredential(arg0 string, arg1 []string) (*azidentity.ClientCertificateCredential, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "FPNewClientCertificateCredential", arg0)
|
||||
ret := m.ctrl.Call(m, "FPNewClientCertificateCredential", arg0, arg1)
|
||||
ret0, _ := ret[0].(*azidentity.ClientCertificateCredential)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// FPNewClientCertificateCredential indicates an expected call of FPNewClientCertificateCredential.
|
||||
func (mr *MockInterfaceMockRecorder) FPNewClientCertificateCredential(arg0 any) *gomock.Call {
|
||||
func (mr *MockInterfaceMockRecorder) FPNewClientCertificateCredential(arg0, arg1 any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FPNewClientCertificateCredential", reflect.TypeOf((*MockInterface)(nil).FPNewClientCertificateCredential), arg0)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FPNewClientCertificateCredential", reflect.TypeOf((*MockInterface)(nil).FPNewClientCertificateCredential), arg0, arg1)
|
||||
}
|
||||
|
||||
// FeatureIsSet mocks base method.
|
||||
|
|
|
@ -21,7 +21,7 @@ type authorizer struct {
|
|||
}
|
||||
|
||||
func (a *authorizer) Rebuild() error {
|
||||
auth, err := a.env.FPAuthorizer(a.tenantID, a.env.Environment().ResourceManagerScope)
|
||||
auth, err := a.env.FPAuthorizer(a.tenantID, nil, a.env.Environment().ResourceManagerScope)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -125,7 +125,7 @@ func (dv *openShiftClusterDynamicValidator) Dynamic(ctx context.Context) error {
|
|||
}
|
||||
|
||||
tenantID := dv.subscriptionDoc.Subscription.Properties.TenantID
|
||||
fpClientCred, err := dv.env.FPNewClientCertificateCredential(tenantID)
|
||||
fpClientCred, err := dv.env.FPNewClientCertificateCredential(tenantID, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -4,10 +4,10 @@ import (
|
|||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/arm"
|
||||
azcloud "github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
|
||||
"github.com/Azure/msi-dataplane/pkg/dataplane/swagger"
|
||||
|
@ -17,6 +17,7 @@ var (
|
|||
// Errors returned when processing idenities
|
||||
errDecodeClientSecret = errors.New("failed to decode client secret")
|
||||
errParseCertificate = errors.New("failed to parse certificate")
|
||||
errParseResourceID = errors.New("failed to parse resource ID")
|
||||
errNilField = errors.New("expected non nil field in identity")
|
||||
errNoUserAssignedMSIs = errors.New("credentials object does not contain user-assigned managed identities")
|
||||
errResourceIDNotFound = errors.New("resource ID not found in user-assigned managed identity")
|
||||
|
@ -49,10 +50,20 @@ func (c CredentialsObject) IsUserAssigned() bool {
|
|||
|
||||
// Get an AzIdentity credential for the given user-assigned identity resource ID
|
||||
// Clients can use the credential to get a token for the user-assigned identity
|
||||
func (u UserAssignedIdentities) GetCredential(resourceID string) (*azidentity.ClientCertificateCredential, error) {
|
||||
func (u UserAssignedIdentities) GetCredential(requestedResourceID string) (*azidentity.ClientCertificateCredential, error) {
|
||||
requestedARMResourceID, err := arm.ParseResourceID(requestedResourceID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%w for requested resource ID %s: %w", errParseResourceID, requestedResourceID, err)
|
||||
}
|
||||
requestedResourceID = requestedARMResourceID.String()
|
||||
|
||||
for _, id := range u.ExplicitIdentities {
|
||||
if id != nil && id.ResourceID != nil {
|
||||
if *id.ResourceID == resourceID {
|
||||
idARMResourceID, err := arm.ParseResourceID(*id.ResourceID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%w for identity resource ID %s: %w", errParseResourceID, *id.ResourceID, err)
|
||||
}
|
||||
if requestedResourceID == idARMResourceID.String() {
|
||||
return getClientCertificateCredential(*id, u.cloud)
|
||||
}
|
||||
}
|
||||
|
@ -61,6 +72,15 @@ func (u UserAssignedIdentities) GetCredential(resourceID string) (*azidentity.Cl
|
|||
return nil, errResourceIDNotFound
|
||||
}
|
||||
|
||||
func getAzCoreCloud(cloud string) azcloud.Configuration {
|
||||
switch cloud {
|
||||
case AzureUSGovCloud:
|
||||
return azcloud.AzureGovernment
|
||||
default:
|
||||
return azcloud.AzurePublic
|
||||
}
|
||||
}
|
||||
|
||||
func getClientCertificateCredential(identity swagger.NestedCredentialsObject, cloud string) (*azidentity.ClientCertificateCredential, error) {
|
||||
// Double check nil pointers so we don't panic
|
||||
fieldsToCheck := map[string]*string{
|
||||
|
@ -86,6 +106,10 @@ func getClientCertificateCredential(identity swagger.NestedCredentialsObject, cl
|
|||
|
||||
// x5c header required: https://eng.ms/docs/products/arm/rbac/managed_identities/msionboardingrequestingatoken
|
||||
SendCertificateChain: true,
|
||||
|
||||
// Disable instance discovery because MSI credential may have regional AAD endpoint that instance discovery endpoint doesn't support
|
||||
// e.g. when MSI credential has westus2.login.microsoft.com, it will cause instance discovery to fail with HTTP 400
|
||||
DisableInstanceDiscovery: true,
|
||||
}
|
||||
|
||||
// Set the regional AAD endpoint
|
||||
|
@ -116,30 +140,26 @@ func validateUserAssignedMSIs(identities []*swagger.NestedCredentialsObject, res
|
|||
if identity == nil {
|
||||
return errNilMSI
|
||||
}
|
||||
|
||||
v := reflect.ValueOf(*identity)
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
if v.Field(i).IsNil() {
|
||||
return fmt.Errorf("%w, field %s", errNilField, v.Type().Field(i).Name)
|
||||
}
|
||||
if identity.ResourceID == nil {
|
||||
return fmt.Errorf("%w, resource ID", errNilField)
|
||||
}
|
||||
resourceIDMap[*identity.ResourceID] = true
|
||||
armResourceID, err := arm.ParseResourceID(*identity.ResourceID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%w for received resource ID %s: %w", errParseResourceID, *identity.ResourceID, err)
|
||||
}
|
||||
|
||||
resourceIDMap[armResourceID.String()] = true
|
||||
}
|
||||
|
||||
for _, resourceID := range resourceIDs {
|
||||
if _, ok := resourceIDMap[resourceID]; !ok {
|
||||
armResourceID, err := arm.ParseResourceID(resourceID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%w for requested resource ID %s: %w", errParseResourceID, resourceID, err)
|
||||
}
|
||||
if _, ok := resourceIDMap[armResourceID.String()]; !ok {
|
||||
return fmt.Errorf("%w, resource ID %s", errResourceIDNotFound, resourceID)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getAzCoreCloud(cloud string) azcloud.Configuration {
|
||||
switch cloud {
|
||||
case AzureUSGovCloud:
|
||||
return azcloud.AzureGovernment
|
||||
default:
|
||||
return azcloud.AzurePublic
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
|
||||
type KeyVaultClient interface {
|
||||
DeleteSecret(ctx context.Context, name string, options *azsecrets.DeleteSecretOptions) (azsecrets.DeleteSecretResponse, error)
|
||||
GetDeletedSecret(ctx context.Context, name string, options *azsecrets.GetDeletedSecretOptions) (azsecrets.GetDeletedSecretResponse, error)
|
||||
GetSecret(ctx context.Context, name string, version string, options *azsecrets.GetSecretOptions) (azsecrets.GetSecretResponse, error)
|
||||
NewListDeletedSecretPropertiesPager(options *azsecrets.ListDeletedSecretPropertiesOptions) *runtime.Pager[azsecrets.ListDeletedSecretPropertiesResponse]
|
||||
NewListSecretPropertiesPager(options *azsecrets.ListSecretPropertiesOptions) *runtime.Pager[azsecrets.ListSecretPropertiesResponse]
|
||||
|
|
15
vendor/github.com/Azure/msi-dataplane/pkg/store/mock_kvclient/zz_generated_mocks.go
сгенерированный
поставляемый
15
vendor/github.com/Azure/msi-dataplane/pkg/store/mock_kvclient/zz_generated_mocks.go
сгенерированный
поставляемый
|
@ -56,6 +56,21 @@ func (mr *MockKeyVaultClientMockRecorder) DeleteSecret(ctx, name, options any) *
|
|||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteSecret", reflect.TypeOf((*MockKeyVaultClient)(nil).DeleteSecret), ctx, name, options)
|
||||
}
|
||||
|
||||
// GetDeletedSecret mocks base method.
|
||||
func (m *MockKeyVaultClient) GetDeletedSecret(ctx context.Context, name string, options *azsecrets.GetDeletedSecretOptions) (azsecrets.GetDeletedSecretResponse, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetDeletedSecret", ctx, name, options)
|
||||
ret0, _ := ret[0].(azsecrets.GetDeletedSecretResponse)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetDeletedSecret indicates an expected call of GetDeletedSecret.
|
||||
func (mr *MockKeyVaultClientMockRecorder) GetDeletedSecret(ctx, name, options any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDeletedSecret", reflect.TypeOf((*MockKeyVaultClient)(nil).GetDeletedSecret), ctx, name, options)
|
||||
}
|
||||
|
||||
// GetSecret mocks base method.
|
||||
func (m *MockKeyVaultClient) GetSecret(ctx context.Context, name, version string, options *azsecrets.GetSecretOptions) (azsecrets.GetSecretResponse, error) {
|
||||
m.ctrl.T.Helper()
|
||||
|
|
|
@ -14,6 +14,17 @@ var (
|
|||
errNilSecretValue = errors.New("secret value is nil")
|
||||
)
|
||||
|
||||
type DeletedSecretProperties struct {
|
||||
Name string
|
||||
RecoveryLevel string
|
||||
DeletedDate time.Time
|
||||
}
|
||||
|
||||
type DeletedSecretResponse struct {
|
||||
CredentialsObject dataplane.CredentialsObject
|
||||
Properties DeletedSecretProperties
|
||||
}
|
||||
|
||||
type MsiKeyVaultStore struct {
|
||||
kvClient KeyVaultClient
|
||||
}
|
||||
|
@ -85,6 +96,42 @@ func (s *MsiKeyVaultStore) GetCredentialsObject(ctx context.Context, secretName
|
|||
return &SecretResponse{CredentialsObject: credentialsObject, Properties: secretProperties}, nil
|
||||
}
|
||||
|
||||
// Get a deleted credentials object from the key vault using the specified secret name.
|
||||
func (s *MsiKeyVaultStore) GetDeletedCredentialsObject(ctx context.Context, secretName string) (*DeletedSecretResponse, error) {
|
||||
response, err := s.kvClient.GetDeletedSecret(ctx, secretName, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if response.Value == nil {
|
||||
return nil, errNilSecretValue
|
||||
}
|
||||
|
||||
var credentialsObject dataplane.CredentialsObject
|
||||
if err := credentialsObject.UnmarshalJSON([]byte(*response.Value)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
deletedSecretProperties := DeletedSecretProperties{
|
||||
Name: secretName,
|
||||
RecoveryLevel: "",
|
||||
DeletedDate: time.Time{},
|
||||
}
|
||||
|
||||
if response.DeletedDate != nil {
|
||||
deletedSecretProperties.DeletedDate = *response.DeletedDate
|
||||
}
|
||||
|
||||
if response.Attributes != nil {
|
||||
// Override defaults if values are present
|
||||
if response.Attributes.RecoveryLevel != nil {
|
||||
deletedSecretProperties.RecoveryLevel = *response.Attributes.RecoveryLevel
|
||||
}
|
||||
}
|
||||
|
||||
return &DeletedSecretResponse{CredentialsObject: credentialsObject, Properties: deletedSecretProperties}, nil
|
||||
}
|
||||
|
||||
// Get a pager for listing credentials objects from the key vault.
|
||||
func (s *MsiKeyVaultStore) GetCredentialsObjectPager() *runtime.Pager[azsecrets.ListSecretPropertiesResponse] {
|
||||
return s.kvClient.NewListSecretPropertiesPager(nil)
|
||||
|
|
|
@ -139,7 +139,7 @@ github.com/Azure/go-autorest/logger
|
|||
# github.com/Azure/go-autorest/tracing v0.6.0
|
||||
## explicit; go 1.12
|
||||
github.com/Azure/go-autorest/tracing
|
||||
# github.com/Azure/msi-dataplane v0.0.6
|
||||
# github.com/Azure/msi-dataplane v0.0.8
|
||||
## explicit; go 1.21
|
||||
github.com/Azure/msi-dataplane/pkg/dataplane
|
||||
github.com/Azure/msi-dataplane/pkg/dataplane/swagger
|
||||
|
|
Загрузка…
Ссылка в новой задаче