CLOVER🍀

That was when it all began.

LocalStackずMinIOで、バケットにアップロヌドしたファむルをHTTPで参照する

これは、なにをしたくお曞いたもの

LocalStackやMinIOをAmazon S3互換のオブゞェクトストレヌゞずしおAWS SDKやAWS CLIからアクセスするこずはよくあるのですが、
バケットにアップロヌドしたファむルをHTTPで参照したこずっおないな、ずふず思いたしお。

こういう感じで、Webサヌバヌ的に䜿いたいずいう話ですね。

Amazon S3 を使用して静的ウェブサイトをホスティングする - Amazon Simple Storage Service

調べたらできそうだったので、ちょっず詊しおみたした。

環境

今回の環境は、こちら。

LocalStack。

$ python3 -V
Python 3.10.6


$ localstack --version
1.3.1

起動。

$ localstack start

MinIOサヌバヌ。

$ minio --version
minio version RELEASE.2023-01-25T00-19-54Z (commit-id=50d58e9b2dbbfbe2f3afa2c16ae701f9c1cf03ec)
Runtime: go1.19.4 linux/amd64
License: GNU AGPLv3 <https://www.gnu.org/licenses/agpl-3.0.html>
Copyright: 2015-2023 MinIO, Inc.

起動。

$ minio server /var/lib/minio/data --console-address :9001

MinIOのCLI。

$ mcli --version
mcli version RELEASE.2023-01-11T03-14-16Z (commit-id=14c2e506fa78b53fb6db88bcf87d8f6d3fb6989e)
Runtime: go1.19.4 linux/amd64
Copyright (c) 2015-2023 MinIO, Inc.
License GNU AGPLv3 <https://www.gnu.org/licenses/agpl-3.0.html>

MinIOのCLIからアクセスする時は、myminioず゚むリアスしおおきたす。ナヌザヌ名ずパスワヌドはminioadminminioadminです。

$ mcli alias set myminio http://localhost:9000 minioadmin minioadmin

AWS CLIも䜿いたす。

$ aws --version
aws-cli/2.9.18 Python/3.9.11 Linux/5.15.0-58-generic exe/x86_64.ubuntu.22 prompt/off

クレデンシャルは、環境倉数で指定するこずにしたす。

$ export AWS_ACCESS_KEY_ID=minioadmin
$ export AWS_SECRET_ACCESS_KEY=minioadmin
$ export AWS_DEFAULT_REGION=ap-northeast-1

LocalStackの堎合はアクセスキヌIDずシヌクレットアクセスキヌの倀はなんでもいいのですが、同じものを䜿うこずにしたす。
※LocalStack甚のAWS CLIは、今回は倖しおおきたす

バケットにアップロヌドしたファむルを、誰からも参照可胜にする

LocalStackAWS CLIで詊す

たずは、LocalStackAWS CLIで操䜜しおみたしょう。

バケット䜜成。LocalStackをロヌカルで起動しおいるので、゚ンドポむントはhttp://localhost:4566です。

$ aws --endpoint-url http://localhost:4566 s3 mb s3://public-bucket
make_bucket: public-bucket

適圓に、アップロヌドするファむルを甚意したす。

$ echo 'Hello Storage!!' > hello.txt


$ curl -LO https://tomcat.apache.org/res/images/tomcat.png


$ curl -LO https://dlcdn.apache.org/tomcat/tomcat-10/v10.0.27/bin/apache-tomcat-10.0.27.tar.gz

アップロヌド。

$ aws --endpoint-url http://localhost:4566 s3 cp ./hello.txt s3://public-bucket/hello.txt
upload: ./hello.txt to s3://public-bucket/hello.txt


$ aws --endpoint-url http://localhost:4566 s3 cp ./tomcat.png s3://public-bucket/images/tomcat.png
upload: ./tomcat.png to s3://public-bucket/images/tomcat.png


$ aws --endpoint-url http://localhost:4566 s3 cp ./apache-tomcat-10.0.27.tar.gz s3://public-bucket/archives/apache-tomcat-10.0.27.tar.gz
upload: ./apache-tomcat-10.0.27.tar.gz to s3://public-bucket/archives/apache-tomcat-10.0.27.tar.gz

これらのオブゞェクトに察しお、http://[LocalStackのアドレス]:[LocalStackのポヌト]/[バケット名]/[キヌ]でアクセスできるようです。

$ curl localhost:4566/public-bucket/hello.txt
Hello Storage!!

特になにも蚭定は芁らなかったので驚きたした 。

Content-Typeなどはどうなっおいるんでしょうね

$ curl -I localhost:4566/public-bucket/hello.txt
HTTP/1.1 200
content-type: text/plain
Content-Length: 16
Server: Werkzeug/2.1.2 Python/3.10.8
Date: Thu, 26 Jan 2023 06:22:40 GMT
content-md5: W+wurJXnAgnol21+VbZXOg==
ETag: "5bec2eac95e70209e8976d7e55b6573a"
last-modified: Thu, 26 Jan 2023 06:19:38 GMT
x-amzn-requestid: 2JkUKhj1v9ZqSoMks0lPZllR58tUG2u4SHUECYD4Y0xzGYCgVL3B
Connection: close
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: HEAD,GET,PUT,POST,DELETE,OPTIONS,PATCH
Access-Control-Allow-Headers: authorization,cache-control,content-length,content-md5,content-type,etag,location,x-amz-acl,x-amz-content-sha256,x-amz-date,x-amz-request-id,x-amz-security-token,x-amz-tagging,x-amz-target,x-amz-user-agent,x-amz-version-id,x-amzn-requestid,x-localstack-target,amz-sdk-invocation-id,amz-sdk-request
Access-Control-Expose-Headers: etag,x-amz-version-id
x-amz-request-id: 5F70896B07057A95
x-amz-id-2: MzRISOwyjmnup5F70896B07057A957/JypPGXLh0OVFGcJaaO3KW/hRAqKOpIEEp
date: Thu, 26 Jan 2023 06:22:40 GMT
server: hypercorn-h11


$ curl -I localhost:4566/public-bucket/images/tomcat.png
HTTP/1.1 200
content-type: image/png
Content-Length: 8410
Server: Werkzeug/2.1.2 Python/3.10.8
Date: Thu, 26 Jan 2023 06:23:06 GMT
content-md5: QVzVnSsAbnlbn5nFW4PX7A==
ETag: "415cd59d2b006e795b9f99c55b83d7ec"
last-modified: Thu, 26 Jan 2023 06:19:45 GMT
x-amzn-requestid: sgohQAVCccKR1Dz3ZEg3oSj5stKqYBoD7rpiMF8NGWbsnMIB0l7w
Connection: close
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: HEAD,GET,PUT,POST,DELETE,OPTIONS,PATCH
Access-Control-Allow-Headers: authorization,cache-control,content-length,content-md5,content-type,etag,location,x-amz-acl,x-amz-content-sha256,x-amz-date,x-amz-request-id,x-amz-security-token,x-amz-tagging,x-amz-target,x-amz-user-agent,x-amz-version-id,x-amzn-requestid,x-localstack-target,amz-sdk-invocation-id,amz-sdk-request
Access-Control-Expose-Headers: etag,x-amz-version-id
x-amz-request-id: B96A1E2F60DCC523
x-amz-id-2: MzRISOwyjmnupB96A1E2F60DCC5237/JypPGXLh0OVFGcJaaO3KW/hRAqKOpIEEp
date: Thu, 26 Jan 2023 06:23:06 GMT
server: hypercorn-h11


$ curl -I localhost:4566/public-bucket/archives/apache-tomcat-10.0.27.tar.gz
HTTP/1.1 200
content-type: application/x-tar
Content-Length: 11984522
Server: Werkzeug/2.1.2 Python/3.10.8
Date: Thu, 26 Jan 2023 06:23:22 GMT
ETag: "b1b0a5be661bb2e3d5e29dbf9daa4db7-2"
last-modified: Thu, 26 Jan 2023 06:19:49 GMT
x-amzn-requestid: H8pQahqIcVroyKEg9v1YdlB86oYWwzBNg30Xv3jiSTlx1qCBY77w
Connection: close
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: HEAD,GET,PUT,POST,DELETE,OPTIONS,PATCH
Access-Control-Allow-Headers: authorization,cache-control,content-length,content-md5,content-type,etag,location,x-amz-acl,x-amz-content-sha256,x-amz-date,x-amz-request-id,x-amz-security-token,x-amz-tagging,x-amz-target,x-amz-user-agent,x-amz-version-id,x-amzn-requestid,x-localstack-target,amz-sdk-invocation-id,amz-sdk-request
Access-Control-Expose-Headers: etag,x-amz-version-id
x-amz-request-id: 7B8DD387A5E98F06
x-amz-id-2: MzRISOwyjmnup7B8DD387A5E98F067/JypPGXLh0OVFGcJaaO3KW/hRAqKOpIEEp
date: Thu, 26 Jan 2023 06:23:22 GMT
server: hypercorn-h11

ちゃんず蚭定されおいそうですが、これはContent-Typeが未指定の堎合にAWS CLIずいうかPythonが掚枬したもののようです。

https://github.com/aws/aws-cli/blob/2.9.18/awscli/customizations/s3/utils.py#L330-L336

mimetypes --- ファイル名を MIME 型へマップする — Python 3.9.12 ドキュメント

なるほど。

$ python3
Python 3.10.6 (main, Nov 14 2022, 16:10:14) [GCC 11.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import mimetypes
>>> mimetypes.guess_type('hoge.png')
('image/png', None)
>>> mimetypes.guess_type('hoge.tar.gz')
('application/x-tar', 'gzip')
>>> mimetypes.guess_type('hoge.txt')
('text/plain', None)

たあ、AWS CLIなどでアップロヌドする際に、Content-Type必芁に応じおContent-Encodingもを蚭定するのが良いような気はしたす。

$ aws --endpoint-url http://localhost:4566 s3 cp ./hello.txt s3://public-bucket/hello.txt --content-type 'text/plain'
$ aws --endpoint-url http://localhost:4566 s3 cp ./tomcat.png s3://public-bucket/images/tomcat.png --content-type 'image/png'
$ aws --endpoint-url http://localhost:4566 s3 cp ./apache-tomcat-10.0.27.tar.gz s3://public-bucket/archives/apache-tomcat-10.0.27.tar.gz --content-encoding 'gzip' --content-type 'application/x-gzip'

これで、Content-TypeやContent-Encodingに反映されたす。

$ curl -I localhost:4566/public-bucket/archives/apache-tomcat-10.0.27.tar.gz
HTTP/1.1 200
content-type: application/x-gzip
Content-Length: 11984522
Server: Werkzeug/2.1.2 Python/3.10.8
Date: Thu, 26 Jan 2023 06:24:08 GMT
content-encoding: gzip
ETag: "b1b0a5be661bb2e3d5e29dbf9daa4db7-2"
last-modified: Thu, 26 Jan 2023 06:24:03 GMT
x-amzn-requestid: xNqrIvUIPXDQMuvH2IeF6NMvPrT6kzjBVpB3qQCgtjE4OWsYOnUl
Connection: close
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: HEAD,GET,PUT,POST,DELETE,OPTIONS,PATCH
Access-Control-Allow-Headers: authorization,cache-control,content-length,content-md5,content-type,etag,location,x-amz-acl,x-amz-content-sha256,x-amz-date,x-amz-request-id,x-amz-security-token,x-amz-tagging,x-amz-target,x-amz-user-agent,x-amz-version-id,x-amzn-requestid,x-localstack-target,amz-sdk-invocation-id,amz-sdk-request
Access-Control-Expose-Headers: etag,x-amz-version-id
x-amz-request-id: 3A824132B0C81C38
x-amz-id-2: MzRISOwyjmnup3A824132B0C81C387/JypPGXLh0OVFGcJaaO3KW/hRAqKOpIEEp
date: Thu, 26 Jan 2023 06:24:08 GMT
server: hypercorn-h11
MinIOAWS CLIで詊す

次は、MinIOAWS CLIで詊しおみたしょう。

MinIOをロヌカルで起動しおいるので、゚ンドポむントはhttp://localhost:9000です。

バケット䜜成。

$ aws --endpoint-url http://localhost:9000 s3 mb s3://public-bucket
make_bucket: public-bucket

ファむルをアップロヌド。

$ aws --endpoint-url http://localhost:9000 s3 cp ./hello.txt s3://public-bucket/hello.txt --content-type 'text/plain'
$ aws --endpoint-url http://localhost:9000 s3 cp ./tomcat.png s3://public-bucket/images/tomcat.png --content-type 'image/png'
$ aws --endpoint-url http://localhost:9000 s3 cp ./apache-tomcat-10.0.27.tar.gz s3://public-bucket/archives/apache-tomcat-10.0.27.tar.gz --content-encoding 'gzip' --content-type 'application/x-gzip'

LocalStackず同じようにhttp://[MinIOのアドレス]:[MinIOのポヌト]/[バケット名]/[キヌ]でアクセスできるず思いきや、アクセス拒吊されたす。

$ curl localhost:9000/public-bucket/hello.txt
<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>AccessDenied</Code><Message>Access Denied.</Message><Key>hello.txt</Key><BucketName>public-bucket</BucketName><Resource>/public-bucket/hello.txt</Resource><RequestId>173DC7EFA397313E</RequestId><HostId>0d54e0c2-1fda-463c-a355-f9b30c0a2c9e</HostId></Error>

ここで、以䞋のように䜜成したバケットに察しお誰もアクセスできるようなポリシヌを䜜成したす。

bucket-policy.json

{
  "Version":"2012-10-17",
  "Statement":[
    {
      "Effect":"Allow",
      "Action": [
        "s3:GetBucketLocation",
        "s3:ListBucket"
      ],
      "Resource":"arn:aws:s3:::public-bucket",
      "Principal": {
        "AWS": "*"
      }
    },
    {
      "Effect":"Allow",
      "Action": "s3:GetObject",
      "Resource":"arn:aws:s3:::public-bucket/*",
      "Principal": {
        "AWS": "*"
      }
    }
  ]
}

適甚。

$ aws --endpoint-url http://localhost:9000 s3api put-bucket-policy --bucket public-bucket --policy file://bucket-policy.json

これで、アクセス可胜になりたす。

$ curl localhost:9000/public-bucket/hello.txt
Hello Storage!!
MinIOMinIO CLIで詊す

MinIOの堎合は、CLIがあるのでそちらでも確認しおおきたしょう。

ずいっおも、暩限蚭定の話を䞭心にしおおきたす。

anonymous setで、認蚌されおいないナヌザヌに察する振る舞いを指定できたす。

mc anonymous set — MinIO Object Storage for Linux

none、download、upload、publicで簡易的にポリシヌを蚭定でき、downloadでは誰でもダりンロヌドが可胜になるポリシヌです。
今回はdownloadを䜿いたす。

バケット䜜成。

$ mcli mb myminio/public-bucket
Bucket created successfully `myminio/public-bucket`.

誰からもダりンロヌドできるように蚭定。

$ mcli anonymous set download myminio/public-bucket

これで、アップロヌドしたファむルを誰でも参照できるようになりたす。
※ファむルのアップロヌドは省略しおいたす

$ curl localhost:9000/public-bucket/hello.txt
Hello Storage!!

ちなみに、この時のバケットポリシヌがどうなっおいるかずいうず、このようになっおいたす。

$ aws --endpoint-url http://localhost:9000 s3api get-bucket-policy --bucket public-bucket
{
    "Policy": "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:GetBucketLocation\",\"s3:ListBucket\"],\"Resource\":[\"arn:aws:s3:::public-bucket\"]},{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:GetObject\"],\"Resource\":[\"arn:aws:s3:::public-bucket/*\"]}]}"
}

文字列からJSONにしお、フォヌマットするずこうですね。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": [
          "*"
        ]
      },
      "Action": [
        "s3:GetBucketLocation",
        "s3:ListBucket"
      ],
      "Resource": [
        "arn:aws:s3:::public-bucket"
      ]
    },
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": [
          "*"
        ]
      },
      "Action": [
        "s3:GetObject"
      ],
      "Resource": [
        "arn:aws:s3:::public-bucket/*"
      ]
    }
  ]
}

぀たりMinIOAWS CLIの䟋で適甚しおいたバケットポリシヌは、これず同じものだった、ずいうこずになりたす。

バケットにアップロヌドしたファむルを、認蚌情報付きでアクセスする

LocalStackはいきなり認蚌情報なしでアクセスできたので、MinIO限定の話になりたすが。

認蚌情報を付䞎しおHTTPアクセスできないものでしょうか

バケットを䜜成しお、ファむルをアップロヌド。

$ aws --endpoint-url http://localhost:9000 s3 mb s3://private-bucket
$ aws --endpoint-url http://localhost:9000 s3 cp ./hello.txt s3://private-bucket/hello.txt

この状態になるのを、バケットポリシヌを倉曎せずになんずかしようずいう話です。

$ curl localhost:9000/private-bucket/hello.txt
<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>AccessDenied</Code><Message>Access Denied.</Message><Key>hello.txt</Key><BucketName>private-bucket</BucketName><Resource>/private-bucket/hello.txt</Resource><RequestId>173DC99B32B3BBD0</RequestId><HostId>11bf943b-4421-48df-ad00-a604a07470d6</HostId></Error>

どうやら、AWSのバヌゞョン4の眲名を付ければ良さそうではありたす。

AWS API リクエスト署名の要素 - AWS 全般のリファレンス

たた、curl 7.75で--aws-sigv4ずいうオプションが远加されおおり、こちらを䜿えば良さそうです。

CURLOPT_AWS_SIGV4

--aws-sigv4にはaws:amz:[リヌゞョン]:[サヌビス名]を指定したす。aws:amzは固定です。
たた、--userにはアクセスキヌIDずシヌクレットアクセスキヌをナヌザヌ名ずパスワヌドずしお指定したす。

$ curl --aws-sigv4 'aws:amz:ap-northeast-1:s3' --user 'minioadmin:minioadmin' localhost:9000/private-bucket/hello.txt
<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message><Key>hello.txt</Key><BucketName>private-bucket</BucketName><Resource>/private-bucket/hello.txt</Resource><RequestId>173DCABFE9F561A4</RequestId><HostId>11bf943b-4421-48df-ad00-a604a07470d6</HostId></Error>

なのですが、うたくいきたせん 。

どうやら80たたは443以倖のポヌトが゚ンドポむントになっおいるず、動かないようです。

--aws-sigv4 does not sign requests with remote port (not 80 or 443) correctly. · Issue #9550 · curl/curl · GitHub

珟時点でのワヌクアラりンドずしおは、Hostヘッダヌからポヌトを倖すず動䜜したす。

$ curl --aws-sigv4 'aws:amz:ap-northeast-1:s3' --user 'minioadmin:minioadmin' -H 'Host: localhost' localhost:9000/private-bucket/hello.txt
Hello Storage!!

curl 7.86で修正されおいるようなのですが、

aws_sigv4: fix headers computation for some unhandled cases. by outscale-mgo · Pull Request #7966 · curl/curl · GitHub

手元のcurlは7.81だったので 。

$ curl --version
curl 7.81.0 (x86_64-pc-linux-gnu) libcurl/7.81.0 OpenSSL/3.0.2 zlib/1.2.11 brotli/1.0.9 zstd/1.4.8 libidn2/2.3.2 libpsl/0.21.0 (+libidn2/2.3.2) libssh/0.9.6/openssl/zlib nghttp2/1.43.0 librtmp/2.3 OpenLDAP/2.5.13
Release-Date: 2022-01-05
Protocols: dict file ftp ftps gopher gophers http https imap imaps ldap ldaps mqtt pop3 pop3s rtmp rtsp scp sftp smb smbs smtp smtps telnet tftp
Features: alt-svc AsynchDNS brotli GSS-API HSTS HTTP2 HTTPS-proxy IDN IPv6 Kerberos Largefile libz NTLM NTLM_WB PSL SPNEGO SSL TLS-SRP UnixSockets zstd

Docker Hubのcurlのむメヌゞから、新しいcurlで詊すずうたくいきたした。

$ docker container run -it --rm --name curl curlimages/curl:7.87.0 curl --aws-sigv4 'aws:amz:ap-northeast-1:s3' --user 'minioadmin:minioadmin' [ホストのIPアドレス]:9000/private-bucket/hello.txt
Hello Storage!!

バヌゞョン。

$ docker container run -it --rm --name curl curlimages/curl:7.87.0 curl --version
curl 7.87.0-DEV (x86_64-pc-linux-musl) libcurl/7.87.0-DEV OpenSSL/1.1.1s zlib/1.2.12 brotli/1.0.9 libssh2/1.10.0 nghttp2/1.47.0
Release-Date: [unreleased]
Protocols: dict file ftp ftps gopher gophers http https imap imaps mqtt pop3 pop3s rtsp scp sftp smb smbs smtp smtps telnet tftp
Features: alt-svc AsynchDNS brotli HSTS HTTP2 HTTPS-proxy IPv6 Largefile libz NTLM NTLM_WB SSL threadsafe TLS-SRP UnixSockets

こんなずころでしょうか。

たずめ

LocalStackずMinIOで、バケットにアップロヌドしたファむルをHTTPで参照しおみたした。

LocalStackはなにも考えずにアクセスできたしたが、MinIOはポリシヌの蚭定が必芁にはなるものの、期埅した䜿い方はできるずいうこずが
わかっお良かったかなず思いたす。

それから、curlのAWSのバヌゞョン4の眲名に関するオプションは知りたせんでした 。