vagrant-box-s3 0.1.3 → 0.1.5

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: 857a4297cb7c77e6fc882a495a81de46e19ec48481e69394450349f4d2ab1462
4
- data.tar.gz: 54fbc90963cefabf0318fadf73ef4e2370c4438862c75a00041fa727fd4f0780
3
+ metadata.gz: 9a2bc5d3cadb3cdcb261f206f5ca46fe0b210ef3514bcc9072176d85222f9e24
4
+ data.tar.gz: 9044ae220e16806ba95a48c94bf147bf5df4b418cd8181bf1a9cab7ac04219ef
5
5
  SHA512:
6
- metadata.gz: 15d7d800c9636bdcc0fbcab656b46d041f57ee018ac20220689135952289603d9dece21ef7b5c7b8700ca9672ba4e7c4231e09d25b1eade790cc7fdd05e7b39b
7
- data.tar.gz: 141d2ca407dfda8c5fa8516732dbbafea8c19a15d9c451645a817b14f177a68362797fb22b57726472acbf9a352758440fc376e2f82b08c97031d6e9be8b6296
6
+ metadata.gz: 24cf532f08f551c08dec67c11b94672bf660d73b985d2d4b35ab35e6413c6d9b6ff709b15088192e7fd006cbd0c76e11dbb0bea8f5f9dafd914e411eeaa9f9e3
7
+ data.tar.gz: a15234a433f1aa2d3f2968ad98c2fc9fb29e11d269361cbd6fc2fbeb10c4fdaaa4dd47d7e4a395fc6fcec5bbb24a4dec184493bc43e4781594a8a8b4e4ca71cf
data/README.md CHANGED
@@ -11,8 +11,9 @@ Use Vagrant boxes stored in Amazon S3 private buckets.
11
11
 
12
12
  ## Features
13
13
 
14
- This plugin works by monkey patching `Vagrant::Util::Downloader`, extending the core Downloader class in Vagrant to
15
- override the `execute_curl` method to replace S3 box URLs with pre-signed S3 URLs.
14
+ This plugin works using the `authenticate_box_url` hook to replace S3 URLs with presigned URLs and monkey
15
+ patching `Vagrant::Util::Downloader`, extending the core Downloader class in Vagrant to override the `head` method
16
+ used when fetching box metadata URLs from S3.
16
17
 
17
18
  ## Installation
18
19
 
@@ -55,22 +56,22 @@ You can also use your credentials file to create a profile. Select the appropria
55
56
 
56
57
  You can use any valid HTTP(S) URL for your box URL:
57
58
 
58
- #### Path-Style URLs
59
-
60
- Specify the bucket name in the path of the URL. AWS has deprecated path-style URLs, but they might still be seen or used in legacy systems.
59
+ #### Virtual-Hosted-Style URLs
61
60
 
62
- - Format: https://s3.Region.amazonaws.com/bucket-name/key-name
63
- - Example: https://s3.eu-west-1.amazonaws.com/mybucket/mybox.box
61
+ Virtual-hosted-style URLs use the bucket name as a subdomain. This is the recommended and most commonly used format.
64
62
 
63
+ | Format | Example |
64
+ |----------------------------------------------|------------------------------------------------------------|
65
+ | `https://BUCKET.s3.REGION.amazonaws.com/KEY` | `https://mybucket.s3.eu-west-1.amazonaws.com/mybox.box` |
65
66
 
66
- - Format: https://s3-Region.amazonaws.com/bucket-name/keyname
67
- - Example: https://s3-eu-west-1.amazonaws.com/bucket-name/mybox.box
67
+ #### Path-Style URLs
68
68
 
69
- #### Virtual-Hosted-Style URLs
70
- Virtual-hosted-style URLs use the bucket name as a subdomain. This is the recommended and most commonly used format.
69
+ Specify the bucket name in the path of the URL. AWS has deprecated path-style URLs, but they might still be seen or used in legacy systems.
71
70
 
72
- - Format: https://bucket-name.s3.Region.amazonaws.com/key-name
73
- - Example: https://mybucket.s3.eu-west-1.amazonaws.com/mybox.box
71
+ | Format | Example |
72
+ |----------------------------------------------|------------------------------------------------------------|
73
+ | `https://s3.REGION.amazonaws.com/BUCKET/KEY` | `https://s3.eu-west-1.amazonaws.com/mybucket/mybox.box` |
74
+ | `https://s3-REGION.amazonaws.com/BUCKET/KEY` | `https://s3-eu-west-1.amazonaws.com/bucket-name/mybox.box` |
74
75
 
75
76
  ### IAM configuration
76
77
 
@@ -123,15 +124,15 @@ Update the current version in `lib/vagrant-box-s3/version.rb`.
123
124
 
124
125
  ### Dev build and test
125
126
 
126
- To build the plugin, use `rake build`, this will create a file with the current version number, e.g. `pkg/vagrant-box-s3-0.1.2.gem`.
127
+ To build the plugin, use `rake build`, this will create a file with the current version number, e.g. `pkg/vagrant-box-s3-{VERSION}.gem`.
127
128
 
128
129
  Remove the old version:
129
130
 
130
- vagrant plugin uninstall vagrant-box-s3
131
+ vagrant plugin uninstall vagrant-box-s3 --local
131
132
 
132
133
  Testing the plugin requires installing into vagrant from the build:
133
134
 
134
- vagrant plugin install ../vagrant-box-s3/pkg/vagrant-box-s3-0.1.2.gem
135
+ vagrant plugin install ../vagrant-box-s3/pkg/vagrant-box-s3-{VERSION}.gem
135
136
 
136
137
  Then running a command that will trigger box URL related actions, such as `vagrant up`, `vagrant box update` etc. with the `--debug` flag.
137
138
 
@@ -4,47 +4,24 @@ module Vagrant
4
4
  module Util
5
5
  class Downloader
6
6
 
7
- def aws_auth_download(options, subprocess_options, &data_proc)
8
- # Get URL from options, which is the last option in the list.
9
- url = options.last
7
+ alias_method :original_head, :head
10
8
 
11
- # Determine method from curl command -I flag existence.
12
- method = options.any? { |o| o == '-I' } ? :head_object : :get_object
9
+ def head
10
+ if ::VagrantPlugins::BoxS3::Utils.is_s3_manifest(@source)
11
+ options, subprocess_options = self.options
12
+ options.unshift("-i")
13
+ options << @source
13
14
 
14
- # Generate pre-signed URL from S3 URL.
15
- presigned_url = VagrantPlugins::BoxS3::Utils.presign_url(method, url, @logger)
15
+ @logger.info("HEAD (Override): #{@source}")
16
+ result = execute_curl(options, subprocess_options)
16
17
 
17
- # Update URL in options.
18
- url.replace(presigned_url.to_s)
19
-
20
- # Call original execute_curl (aliased).
21
- execute_curl_without_aws_auth(options, subprocess_options, &data_proc)
22
-
23
- rescue Aws::Errors::MissingCredentialsError, Aws::Sigv4::Errors::MissingCredentialsError => e
24
- message = "Missing AWS credentials: #{e.message}"
25
- @logger.error(message) if defined?(@logger)
26
- raise Errors::DownloaderError, message: message
27
- rescue Aws::S3::Errors::Forbidden => e
28
- message = "403 Forbidden: #{e.message}"
29
- raise Errors::DownloaderError, message: message
30
- rescue => e
31
- raise Errors::DownloaderError, message: e
32
- end
33
-
34
- def execute_curl_with_aws_auth(options, subprocess_options, &data_proc)
35
- options = options.dup
36
- url = options.find { |o| o =~ /^http/ }
37
-
38
- if url && url.include?('amazonaws.com')
39
- aws_auth_download(options, subprocess_options, &data_proc)
18
+ headers, _body = result.stdout.split("\r\n\r\n", 2)
19
+ headers
40
20
  else
41
- execute_curl_without_aws_auth(options, subprocess_options, &data_proc)
21
+ original_head
42
22
  end
43
23
  end
44
24
 
45
- alias execute_curl_without_aws_auth execute_curl
46
- alias execute_curl execute_curl_with_aws_auth
47
-
48
25
  end
49
26
  end
50
27
  end
@@ -0,0 +1,70 @@
1
+ require 'log4r'
2
+ require 'vagrant-box-s3/utils'
3
+
4
+ module VagrantPlugins
5
+ module BoxS3
6
+ class Urls
7
+ def initialize(app, env)
8
+ @app = app
9
+ @logger = Log4r::Logger.new('vagrant::plugins::box_s3')
10
+ end
11
+
12
+ def call(env)
13
+ # Assume 'env[:box_urls]' contains the original URLs that need authentication
14
+ original_urls = env[:box_urls]
15
+
16
+ # Your logic to authenticate the URLs goes here
17
+ # This is just an example, replace it with your actual authentication mechanism
18
+ authenticated_urls = original_urls.map do |url|
19
+ presign_url(url)
20
+ end
21
+
22
+ # Ensure the authenticated URLs are set back in the environment
23
+ env[:box_urls] = authenticated_urls
24
+
25
+ # Continue the middleware chain
26
+ @app.call(env)
27
+ end
28
+
29
+ private
30
+
31
+ # Pre-sign an s3 URL, with given method.
32
+ def presign_url(url)
33
+
34
+ # Check if the URL is an S3 URL.
35
+ if !Utils.is_s3_url(url)
36
+ @logger.info("Skipping presigner for #{url}")
37
+ return url
38
+ end
39
+
40
+ @logger.info("Discovered S3 URL: #{url}")
41
+
42
+ region, bucket, key = Utils.parse_s3_url(url)
43
+
44
+ profile = ENV['AWS_PROFILE']
45
+
46
+ @logger.debug("Region: #{region}")
47
+ @logger.debug("Bucket: #{bucket}")
48
+ @logger.debug("Key: #{key}")
49
+ @logger.debug("Profile: #{profile}")
50
+
51
+ client = Aws::S3::Client.new(
52
+ profile: profile,
53
+ region: region
54
+ )
55
+ presigner = Aws::S3::Presigner.new(client: client)
56
+
57
+ presigned_url = presigner.presigned_url(
58
+ :get_object,
59
+ bucket: bucket,
60
+ key: key,
61
+ expires_in: 3600
62
+ ).to_s
63
+
64
+ @logger.debug("Pre-signed URL: #{presigned_url}")
65
+
66
+ return presigned_url
67
+ end
68
+ end
69
+ end
70
+ end
@@ -7,13 +7,32 @@ module VagrantPlugins
7
7
 
8
8
  # Match host style URLs, e.g.
9
9
  # https://bucket-name.s3.Region.amazonaws.com/key-name
10
- S3_URL_HOST_REGEX = %r{^https?://([\w\-\.]+)\.s3\.([\w\-]+)\.amazonaws\.com/([^?]+)}
10
+ # https://bucket-name.s3-Region.amazonaws.com/key-name
11
+ S3_URL_HOST_REGEX = %r{^https?://([\w\-\.]+)\.s3[-\.]([\w\-]+)\.amazonaws\.com/([^?]+)}
11
12
 
12
13
  # Match path style URLs e.g.
13
14
  # https://s3.Region.amazonaws.com/bucket-name/key-name
14
15
  # https://s3-Region.amazonaws.com/bucket-name/keyname
15
16
  S3_URL_PATH_REGEX = %r{^https?://s3[-\.]([\w\-]+)\.amazonaws\.com/([^/]+)/([^?]+)}
16
17
 
18
+ # Check if URL matches S3 URLs.
19
+ def self.is_s3_url(url)
20
+ # Check if the URL matches either the host style or path style S3 URL
21
+ matches_host_style = !!(url =~ S3_URL_HOST_REGEX)
22
+ matches_path_style = !!(url =~ S3_URL_PATH_REGEX)
23
+
24
+ # Return true if either match is found, false otherwise
25
+ matches_host_style || matches_path_style
26
+ end
27
+
28
+ # Check if the URL is an S3 URL and the filename is 'manifest.json'
29
+ def self.is_s3_manifest(url)
30
+ uri = URI.parse(url)
31
+ filename = File.basename(uri.path)
32
+
33
+ return is_s3_url(url) && filename == 'manifest.json'
34
+ end
35
+
17
36
  # Parse an s3 URL.
18
37
  def self.parse_s3_url(url)
19
38
  region = bucket = key = nil
@@ -32,66 +51,6 @@ module VagrantPlugins
32
51
  return region, bucket, key
33
52
  end
34
53
 
35
- # Remove presigned URL params from box URL.
36
- # We do this as URLs can be cached and do not want to want
37
- # to include previously presigned URL parameters.
38
- def self.remove_presigned_params(url)
39
- # Parse the URL
40
- uri = URI.parse(url)
41
-
42
- # Split the query string into parameters
43
- query_params = URI.decode_www_form(uri.query || '').to_h
44
-
45
- # Remove any parameters that start with 'X-Amz-'
46
- query_params.reject! { |k, _| k.start_with?('X-Amz-') }
47
-
48
- # Check if there are any query parameters left
49
- if query_params.empty?
50
- # If no query parameters left, set uri.query to nil to remove the '?'
51
- uri.query = nil
52
- else
53
- # Reconstruct the query string without AWS presigned parameters
54
- uri.query = URI.encode_www_form(query_params)
55
- end
56
-
57
- return uri.to_s
58
- end
59
-
60
- # Pre-sign an s3 URL, with given method.
61
- def self.presign_url(method, url, logger)
62
-
63
- url = remove_presigned_params(url)
64
-
65
- logger.info("BoxS3: Generating signed URL for #{method.upcase}")
66
- logger.info("BoxS3: Discovered S3 URL: #{url}")
67
-
68
- region, bucket, key = parse_s3_url(url)
69
-
70
- profile = ENV['AWS_PROFILE']
71
-
72
- logger.debug("BoxS3: Region: #{region}")
73
- logger.debug("BoxS3: Bucket: #{bucket}")
74
- logger.debug("BoxS3: Key: #{key}")
75
- logger.debug("BoxS3: Profile: #{profile}")
76
-
77
- client = Aws::S3::Client.new(
78
- profile: profile,
79
- region: region
80
- )
81
- presigner = Aws::S3::Presigner.new(client: client)
82
-
83
- presigned_url = presigner.presigned_url(
84
- method,
85
- bucket: bucket,
86
- key: key,
87
- expires_in: 3600
88
- ).to_s
89
-
90
- logger.debug("BoxS3: Pre-signed URL: #{presigned_url}")
91
-
92
- return presigned_url
93
- end
94
-
95
54
  end
96
55
  end
97
56
  end
@@ -1,5 +1,5 @@
1
1
  module VagrantPlugins
2
2
  module BoxS3
3
- VERSION = '0.1.3'
3
+ VERSION = '0.1.5'
4
4
  end
5
5
  end
@@ -1,4 +1,5 @@
1
1
  require 'vagrant'
2
+ require 'vagrant-box-s3/urls'
2
3
 
3
4
  module VagrantPlugins
4
5
  module BoxS3
@@ -9,6 +10,10 @@ module VagrantPlugins
9
10
  require_relative 'vagrant-box-s3/downloader'
10
11
  end
11
12
 
13
+ action_hook(:vagrant_box_s3_url, :authenticate_box_url) do |hook|
14
+ hook.prepend(Urls)
15
+ end
16
+
12
17
  end
13
18
  end
14
19
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vagrant-box-s3
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steve Whiteley
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-02-19 00:00:00.000000000 Z
11
+ date: 2024-10-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk-s3
@@ -63,6 +63,7 @@ files:
63
63
  - README.md
64
64
  - lib/vagrant-box-s3.rb
65
65
  - lib/vagrant-box-s3/downloader.rb
66
+ - lib/vagrant-box-s3/urls.rb
66
67
  - lib/vagrant-box-s3/utils.rb
67
68
  - lib/vagrant-box-s3/version.rb
68
69
  homepage: https://github.com/memiah/vagrant-box-s3