terraspace_plugin_azurerm 0.2.2 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
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