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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b3ff4bc13ad8e73d40b985420c107ef791d652bde858092271a239715ec6b824
4
- data.tar.gz: cdbc5ddac31c0c4fad5676ea802810fd9982f02a59f3347bf72d4e407f7abec7
3
+ metadata.gz: bfebfed0cf4e44986ab752e4ff8f642da04b3037b37c869811a49f4cdb6f4959
4
+ data.tar.gz: 7525c37602f54facae4281a53961a3531f8238aa2931e76cf11e0535a1042fe2
5
5
  SHA512:
6
- metadata.gz: 878dc0469567622cd0bf3ef0c378ae5ba9962035511110fdb057892873d0d4e67cf0e00c2173cc52904ea9d2a58d7c2062b1bac8673a8dd45c03bb946e220149
7
- data.tar.gz: f9f776fc7ad11500b9f29c57a141012b883295f59e25c67d7393d07a6dde2aadaf71f7e2322848bdf67ba5feaebce3553c49a4004632e83f9fc5026b965278bf
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](Pluginazurerm)
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](Pluginazurerm), [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:
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
- AZURE_CLIENT_ID
41
- AZURE_CLIENT_SECRET
40
+ ARM_CLIENT_ID
41
+ ARM_CLIENT_SECRET
42
42
 
43
- There's other env variables can also be set, but are generally inferred.
43
+ Other env variables can be optionally set:
44
44
 
45
- AZURE_TENANT_ID
46
- AZURE_SUBSCRIPTION_ID
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('terraform-resources-:LOCATION') %>"
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
- client_id = ENV['AZURE_CLIENT_ID']
7
- client_secret = ENV['AZURE_CLIENT_SECRET']
8
- subscription_id = ENV['AZURE_SUBSCRIPTION_ID'] || AzureInfo.subscription_id
9
- tenant_id = ENV['AZURE_TENANT_ID'] || AzureInfo.tenant_id
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
- provider = MsRestAzure::ApplicationTokenProvider.new(tenant_id, client_id, client_secret)
12
- credentials = MsRest::TokenCredentials.new(provider)
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::Profiles::Latest::Mgmt
10
- include Azure::Storage::Profiles::Latest::Mgmt::Models
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
- Client.new(client_options)
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
@@ -1,7 +1,6 @@
1
1
  class TerraspacePluginAzurerm::Interfaces::Backend
2
2
  class StorageContainer < Base
3
3
  include TerraspacePluginAzurerm::Clients::Storage
4
- extend Memoist
5
4
 
6
5
  def create
7
6
  if exist?
@@ -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
@@ -0,0 +1,10 @@
1
+ module TerraspacePluginAzurerm::Interfaces
2
+ module Helper
3
+ include Terraspace::Plugin::Helper::Interface
4
+
5
+ def azure_secret(name, options={})
6
+ Secret.new(options).fetch(name, options)
7
+ end
8
+ cache_helper :azure_secret
9
+ end
10
+ end
@@ -0,0 +1,7 @@
1
+ module TerraspacePluginAzurerm
2
+ module Logging
3
+ def logger
4
+ Terraspace.logger
5
+ end
6
+ end
7
+ end
@@ -1,3 +1,3 @@
1
1
  module TerraspacePluginAzurerm
2
- VERSION = "0.2.2"
2
+ VERSION = "0.3.2"
3
3
  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.2.2
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: 2020-09-20 00:00:00.000000000 Z
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: '0'
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: '0'
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.2
182
+ rubygems_version: 3.1.6
179
183
  signing_key:
180
184
  specification_version: 4
181
185
  summary: Terraspace Azurerm Cloud Plugin