providers/azure/azure_provider.go (366 lines of code) (raw):
// Copyright 2019 The Terraformer Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package azure
import (
"context"
"errors"
"fmt"
"os"
"strings"
"github.com/Azure/go-autorest/autorest"
"github.com/hashicorp/go-azure-helpers/authentication"
"github.com/hashicorp/go-azure-helpers/sender"
"github.com/manicminer/hamilton/environments"
"github.com/GoogleCloudPlatform/terraformer/terraformutils"
"github.com/GoogleCloudPlatform/terraformer/terraformutils/providerwrapper"
)
type AzureProvider struct { //nolint
terraformutils.Provider
config authentication.Config
authorizer autorest.Authorizer
resourceGroup string
}
func (p *AzureProvider) setEnvConfig() error {
subscriptionID := os.Getenv("ARM_SUBSCRIPTION_ID")
if subscriptionID == "" {
return errors.New("set ARM_SUBSCRIPTION_ID env var")
}
var auxTenants []string
if v := os.Getenv("ARM_AUXILIARY_TENANT_IDS"); v != "" {
auxTenants = strings.Split(v, ";")
if len(auxTenants) > 3 {
return fmt.Errorf("the provider only supports 3 auxiliary tenant IDs for ARM_AUXILIARY_TENANT_IDS")
}
}
builder := &authentication.Builder{
ClientID: os.Getenv("ARM_CLIENT_ID"),
SubscriptionID: subscriptionID,
TenantID: os.Getenv("ARM_TENANT_ID"),
AuxiliaryTenantIDs: auxTenants,
Environment: os.Getenv("ARM_ENVIRONMENT"),
MetadataHost: os.Getenv("ARM_METADATA_HOSTNAME"),
MsiEndpoint: os.Getenv("ARM_MSI_ENDPOINT"),
ClientSecret: os.Getenv("ARM_CLIENT_SECRET"),
ClientCertPath: os.Getenv("ARM_CLIENT_CERTIFICATE_PATH"),
ClientCertPassword: os.Getenv("ARM_CLIENT_CERTIFICATE_PASSWORD"),
IDTokenRequestToken: os.Getenv("ARM_OIDC_REQUEST_TOKEN"),
IDTokenRequestURL: os.Getenv("ARM_OIDC_REQUEST_URL"),
// Feature Toggles
SupportsAzureCliToken: true,
SupportsClientSecretAuth: true,
SupportsClientCertAuth: true,
SupportsManagedServiceIdentity: os.Getenv("ARM_USE_MSI") != "",
SupportsOIDCAuth: os.Getenv("ARM_USE_OIDC") != "",
UseMicrosoftGraph: os.Getenv("ARM_USE_ADAL") == "",
}
if builder.Environment == "" {
builder.Environment = "public"
}
config, err := builder.Build()
if err != nil {
return nil
}
p.config = *config
return nil
}
func (p *AzureProvider) getAuthorizer() (autorest.Authorizer, error) {
env, err := authentication.DetermineEnvironment(p.config.Environment)
if err != nil {
return nil, err
}
p.config.CustomResourceManagerEndpoint = env.ResourceManagerEndpoint
oauthConfig, err := p.config.BuildOAuthConfig(env.ActiveDirectoryEndpoint)
if err != nil {
return nil, err
}
if oauthConfig == nil {
return nil, fmt.Errorf("unable to configure OAuthConfig for tenant %s", p.config.TenantID)
}
sender := sender.BuildSender("terraformer")
ctx := context.Background()
var auth autorest.Authorizer
if p.config.UseMicrosoftGraph {
hamiltonEnv, ero := environments.EnvironmentFromString(p.config.Environment)
if ero != nil {
return nil, ero
}
auth, err = p.config.GetMSALToken(ctx, hamiltonEnv.ResourceManager, sender, oauthConfig, env.TokenAudience)
} else {
// Deprecated
auth, err = p.config.GetADALToken(ctx, sender, oauthConfig, env.ResourceManagerEndpoint)
}
if err != nil {
return nil, err
}
return auth, nil
}
func (p *AzureProvider) Init(args []string) error {
err := p.setEnvConfig()
if err != nil {
return err
}
authorizer, err := p.getAuthorizer()
if err != nil {
return err
}
p.authorizer = authorizer
p.resourceGroup = args[0]
return nil
}
func (p *AzureProvider) GetName() string {
return "azurerm"
}
func (p *AzureProvider) GetProviderData(arg ...string) map[string]interface{} {
version := providerwrapper.GetProviderVersion(p.GetName())
if strings.Contains(version, "v2.") {
return map[string]interface{}{
"provider": map[string]interface{}{
"azurerm": map[string]interface{}{
// NOTE:
// Workaround for azurerm v2 provider changes
// Tested with azurerm_resource_group under v2.17.0
// https://github.com/terraform-providers/terraform-provider-azurerm/issues/5866#issuecomment-594239342
// https://github.com/hashicorp/terraform/issues/24200#issuecomment-594745861
"features": map[string]interface{}{},
},
},
}
}
return map[string]interface{}{
"provider": map[string]interface{}{
"azurerm": map[string]interface{}{
"version": version,
},
},
}
}
func (AzureProvider) GetResourceConnections() map[string]map[string][]string {
return map[string]map[string][]string{
"analysis": {
"resource_group": []string{"resource_group_name", "name"},
},
"app_service": {
"resource_group": []string{"resource_group_name", "name"},
},
"application_gateway": {
"resource_group": []string{"resource_group_name", "name"},
},
"cosmosdb": {
"resource_group": []string{
"resource_group_name", "name",
"location", "location",
},
},
"container": {
"resource_group": []string{
"resource_group_name", "name",
"location", "location",
},
},
"database": {
"resource_group": []string{
"resource_group_name", "name",
"location", "location",
},
},
"databricks": {
"resource_group": []string{
"resource_group_name", "name",
"managed_resource_group_name", "name",
"location", "location",
},
"storage_account": []string{"storage_account_name", "name"},
"subnet": []string{
"public_subnet_name", "name",
"private_subnet_name", "name",
},
"virtual_network": []string{"virtual_network_id", "id"},
},
"data_factory": {
"resource_group": []string{
"resource_group_name", "name",
"location", "location",
},
"data_factory": []string{
"data_factory_name", "name",
"data_factory_id", "id",
"linked_service_name", "name",
"integration_runtime_name", "name",
},
"databricks": []string{"existing_cluster_id", "id"},
"keyvault": []string{"keyvault_id", "id"},
"storage_account": []string{"storage_account_id", "id"},
},
"disk": {
"resource_group": []string{"resource_group_name", "name"},
},
"dns": {
"resource_group": []string{"resource_group_name", "name"},
},
"eventhub": {
"resource_group": []string{"resource_group_name", "name"},
"eventhub": []string{
"eventhub_name", "name",
"namespace_name", "name",
},
},
"keyvault": {
"resource_group": []string{
"resource_group_name", "name",
"location", "location",
},
},
"load_balancer": {
"resource_group": []string{"resource_group_name", "name"},
},
"network_interface": {
"resource_group": []string{
"resource_group_name", "name",
"location", "location",
},
"subnet": []string{"subnet_id", "id"},
},
"network_security_group": {
"resource_group": []string{
"resource_group_name", "name",
"location", "location",
},
"network_security_group": []string{"network_security_group_name", "name"},
},
"network_watcher": {
"resource_group": []string{
"resource_group_name", "name",
"location", "location",
},
"network_watcher": []string{"network_watcher_name", "name"},
"storage_account": []string{"storage_account_id", "id"},
},
"private_dns": {
"resource_group": []string{"resource_group_name", "name"},
"virtual_network": []string{"virtual_network_id", "id"},
"private_dns": []string{
"zone_name", "name",
"private_dns_zone_name", "name",
},
},
"private_endpoint": {
"resource_group": []string{
"resource_group_name", "name",
"location", "location",
},
"subnet": []string{"subnet_id", "id"},
},
"public_ip": {
"resource_group": []string{
"resource_group_name", "name",
"location", "location",
},
},
"purview": {
"resource_group": []string{"resource_group_name", "name"},
},
"redis": {
"resource_group": []string{"resource_group_name", "name"},
},
"route_table": {
"resource_group": []string{
"resource_group_name", "name",
"location", "location",
},
"route_table": []string{"route_table_name", "name"},
},
"scaleset": {
"resource_group": []string{"resource_group_name", "name"},
},
"ssh_public_key": {
"resource_group": []string{
"resource_group_name", "name",
"location", "location",
},
},
"storage_account": {
"resource_group": []string{
"resource_group_name", "name",
"location", "location",
},
"virtual_network": []string{"virtual_network_subnet_ids", "id"},
},
"storage_blob": {
"storage_account": []string{"storage_account_name", "name"},
"storage_container": []string{"storage_container_name", "name"},
},
"storage_container": {
"storage_account": []string{"storage_account_name", "name"},
},
"synapse": {
"resource_group": []string{
"resource_group_name", "name",
"managed_resource_group_name", "name",
},
"synapse": []string{"synapse_workspace_id", "id"},
},
"subnet": {
"resource_group": []string{"resource_group_name", "name"},
"virtual_network": []string{"virtual_network_name", "name"},
"network_security_group": []string{"network_security_group_id", "id"},
"route_table": []string{"route_table_id", "id"},
"subnet": []string{"subnet_id", "id"},
},
"virtual_machine": {
"resource_group": []string{
"resource_group_name", "name",
"location", "location",
},
"network_interface": []string{"network_interface_ids", "id"},
},
"virtual_network": {
"resource_group": []string{"resource_group_name", "name"},
},
}
}
func (p *AzureProvider) GetSupportedService() map[string]terraformutils.ServiceGenerator {
return map[string]terraformutils.ServiceGenerator{
"analysis": &AnalysisGenerator{},
"app_service": &AppServiceGenerator{},
"application_gateway": &ApplicationGatewayGenerator{},
"cosmosdb": &CosmosDBGenerator{},
"container": &ContainerGenerator{},
"database": &DatabasesGenerator{},
"databricks": &DatabricksGenerator{},
"data_factory": &DataFactoryGenerator{},
"disk": &DiskGenerator{},
"dns": &DNSGenerator{},
"eventhub": &EventHubGenerator{},
"keyvault": &KeyVaultGenerator{},
"load_balancer": &LoadBalancerGenerator{},
"management_lock": &ManagementLockGenerator{},
"network_interface": &NetworkInterfaceGenerator{},
"network_security_group": &NetworkSecurityGroupGenerator{},
"network_watcher": &NetworkWatcherGenerator{},
"private_dns": &PrivateDNSGenerator{},
"private_endpoint": &PrivateEndpointGenerator{},
"public_ip": &PublicIPGenerator{},
"purview": &PurviewGenerator{},
"redis": &RedisGenerator{},
"resource_group": &ResourceGroupGenerator{},
"route_table": &RouteTableGenerator{},
"scaleset": &ScaleSetGenerator{},
"security_center_contact": &SecurityCenterContactGenerator{},
"security_center_subscription_pricing": &SecurityCenterSubscriptionPricingGenerator{},
"ssh_public_key": &SSHPublicKeyGenerator{},
"storage_account": &StorageAccountGenerator{},
"storage_blob": &StorageBlobGenerator{},
"storage_container": &StorageContainerGenerator{},
"synapse": &SynapseGenerator{},
"subnet": &SubnetGenerator{},
"virtual_machine": &VirtualMachineGenerator{},
"virtual_network": &VirtualNetworkGenerator{},
}
}
func (p *AzureProvider) InitService(serviceName string, verbose bool) error {
var isSupported bool
if _, isSupported = p.GetSupportedService()[serviceName]; !isSupported {
return errors.New("azurerm: " + serviceName + " not supported service")
}
p.Service = p.GetSupportedService()[serviceName]
p.Service.SetName(serviceName)
p.Service.SetVerbose(verbose)
p.Service.SetProviderName(p.GetName())
p.Service.SetArgs(map[string]interface{}{
"config": p.config,
"authorizer": p.authorizer,
"resource_group": p.resourceGroup,
})
return nil
}