terraspace_plugin_azurerm 0.2.2 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +13 -0
- data/README.md +9 -7
- data/lib/templates/hcl/project/config/terraform/backend.tf +1 -1
- data/lib/terraspace_plugin_azurerm/clients/options.rb +36 -8
- data/lib/terraspace_plugin_azurerm/clients/storage.rb +5 -3
- data/lib/terraspace_plugin_azurerm/interfaces/backend/storage_container.rb +0 -1
- data/lib/terraspace_plugin_azurerm/interfaces/config.rb +2 -2
- data/lib/terraspace_plugin_azurerm/interfaces/helper/secret/fetcher.rb +112 -0
- data/lib/terraspace_plugin_azurerm/interfaces/helper/secret.rb +26 -0
- data/lib/terraspace_plugin_azurerm/interfaces/helper.rb +10 -0
- data/lib/terraspace_plugin_azurerm/logging.rb +7 -0
- data/lib/terraspace_plugin_azurerm/version.rb +1 -1
- data/lib/terraspace_plugin_azurerm.rb +10 -0
- data/terraspace_plugin_azurerm.gemspec +1 -1
- metadata +11 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: bfebfed0cf4e44986ab752e4ff8f642da04b3037b37c869811a49f4cdb6f4959
|
|
4
|
+
data.tar.gz: 7525c37602f54facae4281a53961a3531f8238aa2931e76cf11e0535a1042fe2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 194ee7307c72d33dabab6067386240c32cadaa995fd064fc25aa9fc61a6027919fe33919afa6b1fc365daf915a7899ef36425516a5ba6ab81fb933143c266dd8
|
|
7
|
+
data.tar.gz: 4a7a9e4f831682a3e2b0d902537d6a9bab1fea6658dfad7f55115cadb1ea8552cc01ea3cb99e6803c90c1d5577ad8e8aed7fafa455d625d11fd38250ce6c5fd5
|
data/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,19 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
This project *loosely tries* to adhere to [Semantic Versioning](http://semver.org/).
|
|
5
5
|
|
|
6
|
+
## [0.3.2] - 2021-11-29
|
|
7
|
+
- [#9](https://github.com/boltops-tools/terraspace_plugin_azurerm/pull/9) change starter resource_group_name to have env
|
|
8
|
+
|
|
9
|
+
## [0.3.1] - 2021-04-15
|
|
10
|
+
- update azure_info dependency
|
|
11
|
+
|
|
12
|
+
## [0.3.0] - 2020-11-15
|
|
13
|
+
- [#5](https://github.com/boltops-tools/terraspace_plugin_azurerm/pull/5) helper and secrets support
|
|
14
|
+
- azure_secret helper
|
|
15
|
+
|
|
16
|
+
## [0.2.3]
|
|
17
|
+
- #4 validate env vars and use older storage client
|
|
18
|
+
|
|
6
19
|
## [0.2.2]
|
|
7
20
|
- #3 fix test template
|
|
8
21
|
|
data/README.md
CHANGED
|
@@ -27,7 +27,7 @@ end
|
|
|
27
27
|
|
|
28
28
|
By default, this plugin will automatically create the:
|
|
29
29
|
|
|
30
|
-
* [resource group](
|
|
30
|
+
* [resource group](https://docs.microsoft.com/en-us/azure/azure-resource-manager/management/manage-resource-groups-portal)
|
|
31
31
|
* [storage account](https://docs.microsoft.com/en-us/azure/storage/common/storage-account-create?tabs=azure-portal)
|
|
32
32
|
* [storage container](https://docs.microsoft.com/en-us/cli/azure/storage/container?view=azure-cli-latest#az-storage-container-create)
|
|
33
33
|
|
|
@@ -35,15 +35,17 @@ The settings generally only apply if the resource does not yet exist yet and is
|
|
|
35
35
|
|
|
36
36
|
## Environment Variables
|
|
37
37
|
|
|
38
|
-
To create the Azure resources like [resource group](
|
|
38
|
+
To create the Azure resources like [resource group](https://docs.microsoft.com/en-us/azure/azure-resource-manager/management/manage-resource-groups-portal), [storage account](https://docs.microsoft.com/en-us/azure/storage/common/storage-account-create?tabs=azure-portal), and [storage container](https://docs.microsoft.com/en-us/cli/azure/storage/container?view=azure-cli-latest#az-storage-container-create) these environment variables are required:
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
ARM_CLIENT_ID
|
|
41
|
+
ARM_CLIENT_SECRET
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
Other env variables can be optionally set:
|
|
44
44
|
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
ARM_TENANT_ID
|
|
46
|
+
ARM_SUBSCRIPTION_ID
|
|
47
|
+
|
|
48
|
+
When not set, their values are inferred from the [az cli](https://docs.microsoft.com/en-us/cli/azure/) settings. For those interested, this is done with the [boltops-tools/azure_info](https://github.com/boltops-tools/azure_info) library.
|
|
47
49
|
|
|
48
50
|
## Contributing
|
|
49
51
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# This is useful because azure storage account names are not allowed special characters and are limited to 24 chars.
|
|
3
3
|
terraform {
|
|
4
4
|
backend "azurerm" {
|
|
5
|
-
resource_group_name = "<%= expansion('
|
|
5
|
+
resource_group_name = "<%= expansion(':ENV-:LOCATION') %>"
|
|
6
6
|
storage_account_name = "<%= expansion('ts:SUBSCRIPTION_HASH:LOCATION:ENV') %>"
|
|
7
7
|
container_name = "terraform-state"
|
|
8
8
|
key = "<%= expansion(':LOCATION/:ENV/:BUILD_DIR/terraform.tfstate') %>"
|
|
@@ -3,21 +3,49 @@ module TerraspacePluginAzurerm::Clients
|
|
|
3
3
|
extend Memoist
|
|
4
4
|
|
|
5
5
|
def client_options
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
o = base_client_options
|
|
7
|
+
o[:credentials] = credentials
|
|
8
|
+
o
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def credentials
|
|
12
|
+
o = base_client_options
|
|
13
|
+
provider = MsRestAzure::ApplicationTokenProvider.new(o[:tenant_id], o[:client_id], o[:client_secret])
|
|
14
|
+
MsRest::TokenCredentials.new(provider)
|
|
15
|
+
end
|
|
10
16
|
|
|
11
|
-
|
|
12
|
-
|
|
17
|
+
def base_client_options
|
|
18
|
+
# AZURE_* is used by ruby generally.
|
|
19
|
+
# ARM_* is used by Terraform azurerm provider: https://www.terraform.io/docs/providers/azurerm/index.html
|
|
20
|
+
# Favor ARM_ because this plugin is designed for Terraspace.
|
|
21
|
+
client_id = ENV['ARM_CLIENT_ID'] || ENV['AZURE_CLIENT_ID']
|
|
22
|
+
client_secret = ENV['ARM_CLIENT_SECRET'] || ENV['AZURE_CLIENT_SECRET']
|
|
23
|
+
subscription_id = ENV['ARM_SUBSCRIPTION_ID'] || ENV['AZURE_SUBSCRIPTION_ID'] || AzureInfo.subscription_id
|
|
24
|
+
tenant_id = ENV['ARM_TENANT_ID'] || ENV['AZURE_TENANT_ID'] || AzureInfo.tenant_id
|
|
13
25
|
|
|
14
|
-
{
|
|
26
|
+
o = {
|
|
15
27
|
tenant_id: tenant_id,
|
|
16
28
|
client_id: client_id,
|
|
17
29
|
client_secret: client_secret,
|
|
18
30
|
subscription_id: subscription_id,
|
|
19
|
-
credentials: credentials
|
|
20
31
|
}
|
|
32
|
+
validate_base_options!(o)
|
|
33
|
+
o
|
|
34
|
+
end
|
|
35
|
+
memoize :base_client_options
|
|
36
|
+
|
|
37
|
+
def validate_base_options!(options)
|
|
38
|
+
vars = []
|
|
39
|
+
options.each do |k,v|
|
|
40
|
+
vars << "ARM_#{k}".upcase if v.nil?
|
|
41
|
+
end
|
|
42
|
+
return if vars.empty?
|
|
43
|
+
|
|
44
|
+
logger.error "ERROR: Required Azure env variables missing. Please set these env variables:".color(:red)
|
|
45
|
+
vars.each do |var|
|
|
46
|
+
logger.error " #{var}"
|
|
47
|
+
end
|
|
48
|
+
exit 1
|
|
21
49
|
end
|
|
22
50
|
end
|
|
23
51
|
end
|
|
@@ -6,8 +6,8 @@ module TerraspacePluginAzurerm::Clients
|
|
|
6
6
|
extend Memoist
|
|
7
7
|
|
|
8
8
|
# Include SDK modules to ease access to Storage classes.
|
|
9
|
-
include Azure::Storage::
|
|
10
|
-
include Azure::Storage::
|
|
9
|
+
include Azure::Storage::Mgmt::V2019_06_01
|
|
10
|
+
include Azure::Storage::Mgmt::V2019_06_01::Models
|
|
11
11
|
|
|
12
12
|
def storage_accounts
|
|
13
13
|
mgmt.storage_accounts
|
|
@@ -19,7 +19,9 @@ module TerraspacePluginAzurerm::Clients
|
|
|
19
19
|
memoize :blob_containers
|
|
20
20
|
|
|
21
21
|
def mgmt
|
|
22
|
-
|
|
22
|
+
client = StorageManagementClient.new(credentials)
|
|
23
|
+
client.subscription_id = client_options[:subscription_id]
|
|
24
|
+
client
|
|
23
25
|
end
|
|
24
26
|
memoize :mgmt
|
|
25
27
|
end
|
|
@@ -15,12 +15,12 @@ module TerraspacePluginAzurerm::Interfaces
|
|
|
15
15
|
c = ActiveSupport::OrderedOptions.new
|
|
16
16
|
c.auto_create = true
|
|
17
17
|
c.location = nil # AzureInfo.location not assigned here so it can be lazily inferred
|
|
18
|
-
|
|
18
|
+
c.secrets = ActiveSupport::OrderedOptions.new
|
|
19
|
+
c.secrets.vault = nil
|
|
19
20
|
c.storage_account = ActiveSupport::OrderedOptions.new
|
|
20
21
|
c.storage_account.sku = ActiveSupport::OrderedOptions.new
|
|
21
22
|
c.storage_account.sku.name = "Standard_LRS"
|
|
22
23
|
c.storage_account.sku.tier = "Standard"
|
|
23
|
-
|
|
24
24
|
c
|
|
25
25
|
end
|
|
26
26
|
end
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
require "net/http"
|
|
2
|
+
|
|
3
|
+
class TerraspacePluginAzurerm::Interfaces::Helper::Secret
|
|
4
|
+
class Fetcher
|
|
5
|
+
class Error < StandardError; end
|
|
6
|
+
class VaultNotFoundError < Error; end
|
|
7
|
+
|
|
8
|
+
include TerraspacePluginAzurerm::Logging
|
|
9
|
+
include TerraspacePluginAzurerm::Clients::Options
|
|
10
|
+
|
|
11
|
+
def initialize
|
|
12
|
+
o = base_client_options
|
|
13
|
+
@client_id = o[:client_id]
|
|
14
|
+
@client_secret = o[:client_secret]
|
|
15
|
+
@tenant_id = o[:tenant_id]
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def fetch(name, opts={})
|
|
19
|
+
opts[:vault] ||= TerraspacePluginAzurerm.config.secrets.vault
|
|
20
|
+
get_secret(name, opts)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def get_secret(name, vault: nil, version: nil)
|
|
24
|
+
unless token
|
|
25
|
+
return "ERROR: Unable to authorize and get the temporary token. Double check your ARM_ env variables."
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
version = "/#{version}" if version
|
|
29
|
+
vault_subdomain = vault.downcase
|
|
30
|
+
# Using Azure REST API since the old gem doesnt support secrets https://github.com/Azure/azure-sdk-for-ruby
|
|
31
|
+
# https://docs.microsoft.com/en-us/rest/api/keyvault/getsecret/getsecret
|
|
32
|
+
url = "https://#{vault_subdomain}.vault.azure.net/secrets/#{name}#{version}?api-version=7.1"
|
|
33
|
+
uri = URI(url)
|
|
34
|
+
req = Net::HTTP::Get.new(uri)
|
|
35
|
+
req["Authorization"] = token
|
|
36
|
+
req["Content-Type"] = "application/json"
|
|
37
|
+
|
|
38
|
+
resp = nil
|
|
39
|
+
begin
|
|
40
|
+
resp = send_request(uri, req)
|
|
41
|
+
rescue VaultNotFoundError
|
|
42
|
+
message = "WARN: Vault not found #{vault}"
|
|
43
|
+
logger.info message.color(:yellow)
|
|
44
|
+
return message
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
case resp.code.to_s
|
|
48
|
+
when /^2/
|
|
49
|
+
data = JSON.load(resp.body)
|
|
50
|
+
data['value']
|
|
51
|
+
else
|
|
52
|
+
message = standard_error_message(resp)
|
|
53
|
+
logger.info "WARN: #{message}".color(:yellow)
|
|
54
|
+
message
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def send_request(uri, req)
|
|
59
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
|
60
|
+
http.open_timeout = http.read_timeout = 30
|
|
61
|
+
http.use_ssl = true if uri.scheme == 'https'
|
|
62
|
+
|
|
63
|
+
begin
|
|
64
|
+
http.request(req) # response
|
|
65
|
+
rescue SocketError => e
|
|
66
|
+
# SocketError: Failed to open TCP connection to MISSING-VAULT.vault.azure.net:443 (getaddrinfo: Name or service not known)
|
|
67
|
+
if e.message.include?("vault.azure.net")
|
|
68
|
+
raise VaultNotFoundError.new(e)
|
|
69
|
+
else
|
|
70
|
+
raise
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Secret error handling: 1. network 2. json parse 3. missing secret
|
|
76
|
+
#
|
|
77
|
+
# Azure API responses with decent error message when
|
|
78
|
+
# 403 Forbidden - KeyVault Access Policy needs to be set up
|
|
79
|
+
# 404 Not Found - Secret name is incorrect
|
|
80
|
+
#
|
|
81
|
+
def standard_error_message(resp)
|
|
82
|
+
data = JSON.load(resp.body)
|
|
83
|
+
data['error']['message']
|
|
84
|
+
rescue JSON::ParserError
|
|
85
|
+
resp.body
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
@@token = nil
|
|
89
|
+
def token
|
|
90
|
+
return @@token unless @@token.nil?
|
|
91
|
+
url = "https://login.microsoftonline.com/#{@tenant_id}/oauth2/token"
|
|
92
|
+
uri = URI(url)
|
|
93
|
+
req = Net::HTTP::Get.new(uri)
|
|
94
|
+
req.set_form_data(
|
|
95
|
+
grant_type: "client_credentials",
|
|
96
|
+
client_id: @client_id,
|
|
97
|
+
client_secret: @client_secret,
|
|
98
|
+
resource: "https://vault.azure.net",
|
|
99
|
+
)
|
|
100
|
+
resp = send_request(uri, req)
|
|
101
|
+
data = JSON.load(resp.body)
|
|
102
|
+
if resp.code =~ /^2/
|
|
103
|
+
@@token = "Bearer #{data['access_token']}" if data
|
|
104
|
+
else
|
|
105
|
+
logger.info "WARN: #{data['error_description']}".color(:yellow)
|
|
106
|
+
# return false otherwise error message is used as the bearer toke and get this error:
|
|
107
|
+
# ArgumentError: header field value cannot include CR/LF
|
|
108
|
+
@@token = false
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
require "base64"
|
|
2
|
+
|
|
3
|
+
module TerraspacePluginAzurerm::Interfaces::Helper
|
|
4
|
+
class Secret
|
|
5
|
+
extend Memoist
|
|
6
|
+
include TerraspacePluginAzurerm::Logging
|
|
7
|
+
include TerraspacePluginAzurerm::Clients::Options
|
|
8
|
+
|
|
9
|
+
def initialize(options={})
|
|
10
|
+
@options = options
|
|
11
|
+
@base64 = options[:base64]
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# opts: version, vault
|
|
15
|
+
def fetch(name, opts={})
|
|
16
|
+
value = fetcher.fetch(name, opts)
|
|
17
|
+
value = Base64.strict_encode64(value).strip if @base64
|
|
18
|
+
value
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def fetcher
|
|
22
|
+
Fetcher.new
|
|
23
|
+
end
|
|
24
|
+
memoize :fetcher
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -23,12 +23,22 @@ module TerraspacePluginAzurerm
|
|
|
23
23
|
Interfaces::Config.instance.config
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
+
@@logger = nil
|
|
27
|
+
def logger
|
|
28
|
+
@@logger ||= Terraspace.logger
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def logger=(v)
|
|
32
|
+
@@logger = v
|
|
33
|
+
end
|
|
34
|
+
|
|
26
35
|
extend self
|
|
27
36
|
end
|
|
28
37
|
|
|
29
38
|
Terraspace::Plugin.register("azurerm",
|
|
30
39
|
backend: "azurerm",
|
|
31
40
|
config_class: TerraspacePluginAzurerm::Interfaces::Config,
|
|
41
|
+
helper_class: TerraspacePluginAzurerm::Interfaces::Helper,
|
|
32
42
|
layer_class: TerraspacePluginAzurerm::Interfaces::Layer,
|
|
33
43
|
root: File.dirname(__dir__),
|
|
34
44
|
)
|
|
@@ -23,7 +23,7 @@ Gem::Specification.new do |spec|
|
|
|
23
23
|
spec.require_paths = ["lib"]
|
|
24
24
|
|
|
25
25
|
spec.add_dependency "azure-storage-blob"
|
|
26
|
-
spec.add_dependency "azure_info"
|
|
26
|
+
spec.add_dependency "azure_info", "~> 0.1.2"
|
|
27
27
|
spec.add_dependency "azure_mgmt_resources"
|
|
28
28
|
spec.add_dependency "azure_mgmt_storage"
|
|
29
29
|
spec.add_dependency "memoist"
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: terraspace_plugin_azurerm
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Tung Nguyen
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2021-11-29 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: azure-storage-blob
|
|
@@ -28,16 +28,16 @@ dependencies:
|
|
|
28
28
|
name: azure_info
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
30
30
|
requirements:
|
|
31
|
-
- - "
|
|
31
|
+
- - "~>"
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
|
-
version:
|
|
33
|
+
version: 0.1.2
|
|
34
34
|
type: :runtime
|
|
35
35
|
prerelease: false
|
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
37
|
requirements:
|
|
38
|
-
- - "
|
|
38
|
+
- - "~>"
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
|
-
version:
|
|
40
|
+
version: 0.1.2
|
|
41
41
|
- !ruby/object:Gem::Dependency
|
|
42
42
|
name: azure_mgmt_resources
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -151,8 +151,12 @@ files:
|
|
|
151
151
|
- lib/terraspace_plugin_azurerm/interfaces/backend/storage_container.rb
|
|
152
152
|
- lib/terraspace_plugin_azurerm/interfaces/config.rb
|
|
153
153
|
- lib/terraspace_plugin_azurerm/interfaces/expander.rb
|
|
154
|
+
- lib/terraspace_plugin_azurerm/interfaces/helper.rb
|
|
155
|
+
- lib/terraspace_plugin_azurerm/interfaces/helper/secret.rb
|
|
156
|
+
- lib/terraspace_plugin_azurerm/interfaces/helper/secret/fetcher.rb
|
|
154
157
|
- lib/terraspace_plugin_azurerm/interfaces/layer.rb
|
|
155
158
|
- lib/terraspace_plugin_azurerm/interfaces/summary.rb
|
|
159
|
+
- lib/terraspace_plugin_azurerm/logging.rb
|
|
156
160
|
- lib/terraspace_plugin_azurerm/version.rb
|
|
157
161
|
- terraspace_plugin_azurerm.gemspec
|
|
158
162
|
homepage: https://github.com/boltops-tools/terraspace_plugin_azurerm
|
|
@@ -175,7 +179,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
175
179
|
- !ruby/object:Gem::Version
|
|
176
180
|
version: '0'
|
|
177
181
|
requirements: []
|
|
178
|
-
rubygems_version: 3.1.
|
|
182
|
+
rubygems_version: 3.1.6
|
|
179
183
|
signing_key:
|
|
180
184
|
specification_version: 4
|
|
181
185
|
summary: Terraspace Azurerm Cloud Plugin
|