class MU::Cloud::Azure::User

A user as configured in {MU::Config::BasketofKittens::users}

Public Class Methods

cleanup(**args) click to toggle source

Stub method. Azure resources are cleaned up by removing the parent resource group. @return [void]

# File modules/mu/providers/azure/user.rb, line 143
def self.cleanup(**args)
end
find(**args) click to toggle source

Locate and return cloud provider descriptors of this resource type which match the provided parameters, or all visible resources if no filters are specified. At minimum, implementations of find must honor credentials and cloud_id arguments. We may optionally support other search methods, such as tag_key and tag_value, or cloud-specific arguments like project. See also {MU::MommaCat.findStray}. @param args [Hash]: Hash of named arguments passed via Ruby's double-splat @return [Hash<String,OpenStruct>]: The cloud provider's complete descriptions of matching resources

# File modules/mu/providers/azure/user.rb, line 154
        def self.find(**args)
          found = {}

# XXX Had to register Microsoft.ApiManagement at https://portal.azure.com/#@eglobaltechlabs.onmicrosoft.com/resource/subscriptions/3d20ddd8-4652-4074-adda-0d127ef1f0e0/resourceproviders
# ffs automate this process, it's just like API enabling in GCP

          # Azure resources are namedspaced by resource group. If we weren't
          # told one, we may have to search all the ones we can see.
          resource_groups = if args[:resource_group]
            [args[:resource_group]]
          elsif args[:cloud_id] and args[:cloud_id].is_a?(MU::Cloud::Azure::Id)
            [args[:cloud_id].resource_group]
          else
            MU::Cloud::Azure.resources(credentials: args[:credentials]).resource_groups.list.map { |rg| rg.name }
          end

          if args[:cloud_id]
            id_str = args[:cloud_id].is_a?(MU::Cloud::Azure::Id) ? args[:cloud_id].name : args[:cloud_id]
            resource_groups.each { |rg|
              resp = MU::Cloud::Azure.serviceaccts(credentials: args[:credentials]).user_assigned_identities.get(rg, id_str)
              found[Id.new(resp.id)] = resp if resp
            }
          else
            if args[:resource_group]
              MU::Cloud::Azure.serviceaccts(credentials: args[:credentials]).user_assigned_identities.list_by_resource_group.each { |ident|
                found[Id.new(ident.id)] = ident
              }
            else
              MU::Cloud::Azure.serviceaccts(credentials: args[:credentials]).user_assigned_identities.list_by_subscription.each { |ident|
                found[Id.new(ident.id)] = ident
              }
            end
          end

          found
        end
isGlobal?() click to toggle source

Does this resource type exist as a global (cloud-wide) artifact, or is it localized to a region/zone? @return [Boolean]

# File modules/mu/providers/azure/user.rb, line 130
def self.isGlobal?
  false
end
new(**args) click to toggle source

Initialize this cloud resource object. Calling super will invoke the initializer defined under {MU::Cloud}, which should set the attribtues listed in {MU::Cloud::PUBLIC_ATTRS} as well as applicable dependency shortcuts, like @vpc, for us. @param args [Hash]: Hash of named arguments passed via Ruby's double-splat

Calls superclass method
# File modules/mu/providers/azure/user.rb, line 23
def initialize(**args)
  super

  if !mu_name.nil?
    @mu_name = mu_name
    @cloud_id = Id.new(cloud_desc.id) if @cloud_id and cloud_desc
  else
    @mu_name ||= @deploy.getResourceName(@config["name"], max_length: 31)
  end

end
quality() click to toggle source

Denote whether this resource implementation is experiment, ready for testing, or ready for production use.

# File modules/mu/providers/azure/user.rb, line 136
def self.quality
  MU::Cloud::ALPHA
end
schema(_config) click to toggle source

Cloud-specific configuration properties. @param _config [MU::Config]: The calling MU::Config object @return [Array<Array,Hash>]: List of required fields, and json-schema Hash of cloud-specific configuration parameters for this resource

# File modules/mu/providers/azure/user.rb, line 194
def self.schema(_config)
  toplevel_required = []
  schema = {
    "region" => MU::Config.region_primitive,
    "name" => {
      "type" => "string",
      "description" => "The name of a account to create. Currently, +service+ is the only account type we support in Azure."
    },
    "type" => {
      "type" => "string",
      "description" => "'service' will create a service account (machine credentials) and generate API keys",
      "enum" => ["service"]
    },
    "roles" => {
      "type" => "array",
      "description" => "One or more Azure Authorization roles to associate with this resource.",
      "default" => ["Reader"],
      "items" => {
        "type" => "string",
        "description" => "One or more Azure Authorization roles to associate with this resource. If no roles are specified, we default to +Reader+, which permits read-only access subscription-wide."
      }
    }
  }
  [toplevel_required, schema]
end
validateConfig(user, _configurator) click to toggle source

Cloud-specific pre-processing of {MU::Config::BasketofKittens::users}, bare and unvalidated. @param user [Hash]: The resource to process and validate @param _configurator [MU::Config]: The overall deployment configurator of which this resource is a member @return [Boolean]: True if validation succeeded, False otherwise

# File modules/mu/providers/azure/user.rb, line 224
        def self.validateConfig(user, _configurator)
          ok = true
          user['region'] ||= MU::Cloud::Azure.myRegion(user['credentials'])

#          if user['groups'] and user['groups'].size > 0 and
#             !MU::Cloud::Azure.credConfig(user['credentials'])['masquerade_as']
#            MU.log "Cannot change Azure group memberships in non-GSuite environments.\nVisit https://groups.google.com to manage groups.", MU::ERR
#            ok = false
#          end

          if user['type'] != "service" and user["create_api_key"]
            MU.log "Only service accounts can have API keys in Azure", MU::ERR
            ok = false
          end

          if user['type'] != "service"
            MU.log "Human accounts not yet supported in Azure::User", MU::ERR
            ok = false
          end

          ok
        end

Public Instance Methods

create() click to toggle source

Called automatically by {MU::Deploy#createResources}

# File modules/mu/providers/azure/user.rb, line 36
        def create
          @config['region'] ||= MU::Cloud::Azure.myRegion(@config['credentials'])
          rgroup_name = @deploy.deploy_id+"-"+@config['region'].upcase

          tags = {}
          if !@config['scrub_mu_isms']
            tags = MU::MommaCat.listStandardTags
          end
          if @config['tags']
            @config['tags'].each { |tag|
              tags[tag['key']] = tag['value']
            }
          end

          if @config['type'] == "interactive"
            raise Mu::MuError, "I don't know how to make interactive users in Azure yet"
          else
            ident_obj = MU::Cloud::Azure.serviceaccts(:Identity).new
#            ident_obj.name = @mu_name
            ident_obj.location = @config['region']
            ident_obj.tags = tags
            begin
              MU.log "Creating service account #{@mu_name}"
              resp = MU::Cloud::Azure.serviceaccts(credentials: @config['credentials']).user_assigned_identities.create_or_update(rgroup_name, @mu_name, ident_obj)
              @cloud_id = Id.new(resp.id)
            rescue ::MsRestAzure::AzureOperationError => e
              MU::Cloud::Azure.handleError(e)
            end

            begin
              sleep 1
            end while cloud_desc(use_cache: false).nil? or cloud_desc.client_id.nil?

          end
        end
getSecret() click to toggle source

If we're a managed service identity or otherwise have a URL for fetching our client secret, fetch it and return it. XXX this doesn't work, and may not be intended to @return [String]

# File modules/mu/providers/azure/user.rb, line 76
        def getSecret
          if cloud_desc and cloud_desc.client_secret_url
            cred_hash = MU::Cloud::Azure.getSDKOptions(@credentials)

            token_provider = MsRestAzure::ApplicationTokenProvider.new(
              cred_hash[:tenant_id],
              cred_hash[:client_id],
              cred_hash[:client_secret]
            )
            cred_obj = MsRest::TokenCredentials.new(token_provider)

            client = ::MsRest::ServiceClient.new(cred_obj)
            cloud_desc.client_secret_url.match(/^(http.*?\.azure\.net)(\/.*)/)
            path = Regexp.last_match[2]
#MU.log "Calling into #{base} #{path}"
            promise = client.make_request_async(
              cloud_desc.client_secret_url,
              :get,
              path
            )

            # XXX this is async, need to stop and wait somehow
            promise.then do | result|
              result.response
#              MU.log "RESPONSE", MU::WARN, details: resp
            end
          end
          nil
        end
groom() click to toggle source

Called automatically by {MU::Deploy#createResources}

# File modules/mu/providers/azure/user.rb, line 107
def groom
  if @config['roles']
    @config['roles'].each { |role|
      MU::Cloud.resourceClass("Azure", "Role").assignTo(cloud_desc.principal_id, role_name: role, credentials: @config['credentials'])
    }
  end
end
notify() click to toggle source

Return the metadata for this user configuration @return [Hash]

# File modules/mu/providers/azure/user.rb, line 117
def notify
  description = MU.structToHash(cloud_desc)
  if description
    description.delete(:etag)
    return description
  end
  {
  }
end

Private Instance Methods

bind_human_user() click to toggle source
# File modules/mu/providers/azure/user.rb, line 249
def bind_human_user
end