a8e81ce393
* Initial import of Azure Secrets * Update vendor folder
191 lines
7.1 KiB
Go
191 lines
7.1 KiB
Go
package azuresecrets
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/Azure/azure-sdk-for-go/services/graphrbac/1.6/graphrbac"
|
|
"github.com/Azure/azure-sdk-for-go/services/preview/authorization/mgmt/2018-01-01-preview/authorization"
|
|
"github.com/Azure/go-autorest/autorest"
|
|
"github.com/Azure/go-autorest/autorest/azure/auth"
|
|
"github.com/hashicorp/vault/helper/useragent"
|
|
)
|
|
|
|
// AzureProvider is an interface to access underlying Azure client objects and supporting services.
|
|
// Where practical the original function signature is preserved. client provides higher
|
|
// level operations atop AzureProvider.
|
|
type AzureProvider interface {
|
|
ApplicationsClient
|
|
ServicePrincipalsClient
|
|
RoleAssignmentsClient
|
|
RoleDefinitionsClient
|
|
}
|
|
|
|
type ApplicationsClient interface {
|
|
CreateApplication(ctx context.Context, parameters graphrbac.ApplicationCreateParameters) (graphrbac.Application, error)
|
|
DeleteApplication(ctx context.Context, applicationObjectID string) (autorest.Response, error)
|
|
}
|
|
|
|
type ServicePrincipalsClient interface {
|
|
CreateServicePrincipal(ctx context.Context, parameters graphrbac.ServicePrincipalCreateParameters) (graphrbac.ServicePrincipal, error)
|
|
}
|
|
|
|
type RoleAssignmentsClient interface {
|
|
CreateRoleAssignment(
|
|
ctx context.Context,
|
|
scope string,
|
|
roleAssignmentName string,
|
|
parameters authorization.RoleAssignmentCreateParameters) (authorization.RoleAssignment, error)
|
|
DeleteRoleAssignmentByID(ctx context.Context, roleID string) (authorization.RoleAssignment, error)
|
|
}
|
|
|
|
type RoleDefinitionsClient interface {
|
|
ListRoles(ctx context.Context, scope string, filter string) ([]authorization.RoleDefinition, error)
|
|
GetRoleByID(ctx context.Context, roleID string) (result authorization.RoleDefinition, err error)
|
|
}
|
|
|
|
// provider is a concrete implementation of AzureProvider. In most cases it is a simple passthrough
|
|
// to the appropriate client object. But if the response requires processing that is more practical
|
|
// at this layer, the response signature may different from the Azure signature.
|
|
type provider struct {
|
|
settings *clientSettings
|
|
|
|
appClient *graphrbac.ApplicationsClient
|
|
spClient *graphrbac.ServicePrincipalsClient
|
|
raClient *authorization.RoleAssignmentsClient
|
|
rdClient *authorization.RoleDefinitionsClient
|
|
}
|
|
|
|
// newAzureProvider creates an azureProvider, backed by Azure client objects for underlying services.
|
|
func newAzureProvider(settings *clientSettings) (AzureProvider, error) {
|
|
// build clients that use the GraphRBAC endpoint
|
|
authorizer, err := getAuthorizer(settings, settings.Environment.GraphEndpoint)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var userAgent string
|
|
if settings.PluginEnv != nil {
|
|
userAgent = useragent.PluginString(settings.PluginEnv, "azure-secrets")
|
|
} else {
|
|
userAgent = useragent.String()
|
|
}
|
|
|
|
appClient := graphrbac.NewApplicationsClient(settings.TenantID)
|
|
appClient.Authorizer = authorizer
|
|
appClient.AddToUserAgent(userAgent)
|
|
|
|
spClient := graphrbac.NewServicePrincipalsClient(settings.TenantID)
|
|
spClient.Authorizer = authorizer
|
|
spClient.AddToUserAgent(userAgent)
|
|
|
|
// build clients that use the Resource Manager endpoint
|
|
authorizer, err = getAuthorizer(settings, settings.Environment.ResourceManagerEndpoint)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
raClient := authorization.NewRoleAssignmentsClient(settings.SubscriptionID)
|
|
raClient.Authorizer = authorizer
|
|
raClient.AddToUserAgent(userAgent)
|
|
|
|
rdClient := authorization.NewRoleDefinitionsClient(settings.SubscriptionID)
|
|
rdClient.Authorizer = authorizer
|
|
rdClient.AddToUserAgent(userAgent)
|
|
|
|
p := &provider{
|
|
settings: settings,
|
|
|
|
appClient: &appClient,
|
|
spClient: &spClient,
|
|
raClient: &raClient,
|
|
rdClient: &rdClient,
|
|
}
|
|
|
|
return p, nil
|
|
}
|
|
|
|
// getAuthorizer attempts to create an authorizer, preferring ClientID/Secret if present,
|
|
// and falling back to MSI if not.
|
|
func getAuthorizer(settings *clientSettings, resource string) (authorizer autorest.Authorizer, err error) {
|
|
|
|
if settings.ClientID != "" && settings.ClientSecret != "" && settings.TenantID != "" {
|
|
config := auth.NewClientCredentialsConfig(settings.ClientID, settings.ClientSecret, settings.TenantID)
|
|
config.AADEndpoint = settings.Environment.ActiveDirectoryEndpoint
|
|
config.Resource = resource
|
|
authorizer, err = config.Authorizer()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
} else {
|
|
config := auth.NewMSIConfig()
|
|
config.Resource = resource
|
|
authorizer, err = config.Authorizer()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
return authorizer, nil
|
|
}
|
|
|
|
// CreateApplication create a new Azure application object.
|
|
func (p *provider) CreateApplication(ctx context.Context, parameters graphrbac.ApplicationCreateParameters) (graphrbac.Application, error) {
|
|
return p.appClient.Create(ctx, parameters)
|
|
}
|
|
|
|
// DeleteApplication deletes an Azure application object.
|
|
// This will in turn remove the service principal (but not the role assignments).
|
|
func (p *provider) DeleteApplication(ctx context.Context, applicationObjectID string) (autorest.Response, error) {
|
|
return p.appClient.Delete(ctx, applicationObjectID)
|
|
}
|
|
|
|
// CreateServicePrincipal creates a new Azure service principal.
|
|
// An Application must be created prior to calling this and pass in parameters.
|
|
func (p *provider) CreateServicePrincipal(ctx context.Context, parameters graphrbac.ServicePrincipalCreateParameters) (graphrbac.ServicePrincipal, error) {
|
|
return p.spClient.Create(ctx, parameters)
|
|
}
|
|
|
|
// ListRoles like all Azure roles with a scope (often subscription).
|
|
func (p *provider) ListRoles(ctx context.Context, scope string, filter string) (result []authorization.RoleDefinition, err error) {
|
|
page, err := p.rdClient.List(ctx, scope, filter)
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return page.Values(), nil
|
|
}
|
|
|
|
// GetRoleByID fetches the full role definition given a roleID.
|
|
func (p *provider) GetRoleByID(ctx context.Context, roleID string) (result authorization.RoleDefinition, err error) {
|
|
return p.rdClient.GetByID(ctx, roleID)
|
|
}
|
|
|
|
// CreateRoleAssignment assigns a role to a service principal.
|
|
func (p *provider) CreateRoleAssignment(ctx context.Context, scope string, roleAssignmentName string, parameters authorization.RoleAssignmentCreateParameters) (authorization.RoleAssignment, error) {
|
|
return p.raClient.Create(ctx, scope, roleAssignmentName, parameters)
|
|
}
|
|
|
|
// GetRoleAssignmentByID fetches the full role assignment info given a roleAssignmentID.
|
|
func (p *provider) GetRoleAssignmentByID(ctx context.Context, roleAssignmentID string) (result authorization.RoleAssignment, err error) {
|
|
return p.raClient.GetByID(ctx, roleAssignmentID)
|
|
}
|
|
|
|
// DeleteRoleAssignmentByID deletes a role assignment.
|
|
func (p *provider) DeleteRoleAssignmentByID(ctx context.Context, roleAssignmentID string) (result authorization.RoleAssignment, err error) {
|
|
return p.raClient.DeleteByID(ctx, roleAssignmentID)
|
|
}
|
|
|
|
// ListRoleAssignments lists all role assignments.
|
|
// There is no need for paging; the caller only cares about the the first match and whether
|
|
// there are 0, 1 or >1 items. Unpacking here is a simpler interface.
|
|
func (p *provider) ListRoleAssignments(ctx context.Context, filter string) ([]authorization.RoleAssignment, error) {
|
|
page, err := p.raClient.List(ctx, filter)
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return page.Values(), nil
|
|
}
|