The aim of this challenge is to build an application that exposes an API accepting and serving files. Please document your choices and feel free to ask questions or intermediate code review. TODO: Multipart Upload: https://www.mohitkhare.com/blog/file-upload-golang/ TODO: Use: multipart/form-data (When you are dealing with files you should use multipart/form-data)
A docker-compose is available to start a local instance of Minio (https://github.com/minio/minio):
version: "3"
services:
minio:
image: quay.io/minio/minio
command:
- server
- /data
- --console-address
- :9001
ports:
- "9000:9000"
- "9001:9001"After starting the service (docker-compose up -d), it will be available from 127.0.0.1:9000 with the default credentials minioadmin:minioadmin.
The application is written in Go and should:
- accept files of arbitrary size, encrypt their content, upload them to a Minio bucket
- serve the submitted files. Submitting and reading files from the API should be possible using curl.
- (bonus) upload the file in chunks of configurable size (e.g. 1MB) in the Minio bucket. This mode should be enabled via a configuration. (multipart file upload)
Please send us a link to a public Github repository containing your deliverables within 15 days after receipt of the challenge.
- Copy
./config/example-config.ymlinto./config/dev-config.ymland put your own values
cd docker/minio
docker-compose up -d-
Create
access-key-idandsecret-access-keyfrom minio dashboard (http://127.0.0.1:9001/access-keys/new-account) and copy the values inside./config/dev-config.yml -
Create
encryption-key-idwith:
kes key create dev-keyAnd copy the values inside ./config/dev-config.yml
NOTE: To quickly install kes and mc I created a bash script in ./scripts/installMcAndKes.sh (run bash script)
NOTE: Guide to install and configure kes install mc, kes and configure server side encryption
-
With the running minio docker container (verify with
docker ps) -
Create small and big files (inside project root folder):
mkdir testfiles
dd if=/dev/urandom of=./testfiles/verysmall1MiB bs=1M count=1
dd if=/dev/urandom of=./testfiles/small10MiB bs=1M count=10
dd if=/dev/urandom of=./testfiles/medium20MiB bs=1M count=20
dd if=/dev/urandom of=./testfiles/big100MiB bs=1M count=100- Run test suite (inside project root folder)
go testSERVER_ENVIRONMENT="dev" go run main.gocurl --location --request POST 'http://localhost:8080/files' \
--header 'Content-Type: application/json' \
--data-raw '{
"bucketName":"test",
"objectName": "big",
"filepath": "./testfiles/big100MiB",
"contentType": "application/octet-stream"
}'curl --location --request POST 'http://localhost:8080/files' \
--header 'Content-Type: application/json' \
--data-raw '{
"bucketName":"test",
"objectName": "medium",
"filepath": "./testfiles/medium20MiB",
"contentType": "application/octet-stream"
}'curl --location --request POST 'http://localhost:8080/files' \
--header 'Content-Type: application/json' \
--data-raw '{
"bucketName":"test",
"objectName": "small",
"filepath": "./testfiles/small10MiB",
"contentType": "application/octet-stream"
}'curl --location --request POST 'http://localhost:8080/files' \
--header 'Content-Type: application/json' \
--data-raw '{
"bucketName":"test",
"objectName": "small",
"filepath": "./testfiles/verysmall1MiB",
"contentType": "application/octet-stream"
}'curl --location --request GET 'http://localhost:8080/files/small' \
--header 'Content-Type: application/json' \
--data-raw '{
"bucketName": "test",
"downloadPath": "/tmp/download1.txt"
}'By default minio starts doing multipart upload at 16MiB, one can enforce no multipart upload by setting minio.PutObjectOptions{DisableMultipart: true}
So, by default minio multipart upload enabled and with part-size of 16MiB. (code)
The minimum part size is 5MiB (Part Size Range) Code reference
To enable multipart upload there are 2 parameters in ./config/dev-config.yml:
- enable-multipart-upload: true
- file-chunk-size: 5
Verify Multipart upload with:
mc admin trace -v myminioLook for:
[REQUEST s3.NewMultipartUpload][REQUEST s3.PutObjectPart]PUT /test/big?partNumber=1[REQUEST s3.PutObjectPart]PUT /test/big?partNumber=2[REQUEST s3.PutObjectPart]PUT /test/big?partNumber=n[REQUEST s3.CompleteMultipartUpload]
e.g. By uploading the big file (100MiB) with part-size of 5MiB there will be 20 parts. (20x [REQUEST s3.PutObjectPart])
e.g. By uploading the small file (10MiB) with part-size of 5MiB there will be 2 parts. (2x [REQUEST s3.PutObjectPart])
Source: https://min.io/docs/minio/linux/reference/minio-mc.html#mc-install
curl https://dl.min.io/client/mc/release/linux-amd64/mc \
--create-dirs \
-o $HOME/minio-binaries/mc
chmod +x $HOME/minio-binaries/mc
export PATH=$PATH:$HOME/minio-binaries/
mc --helpmc alias set myminio http://localhost:9000/ ACCESS_KEY SECRET_KEYCheck
mc admin info myminioSource: https://github.com/minio/kes
curl -sSL --tlsv1.2 'https://github.com/minio/kes/releases/latest/download/kes-linux-amd64' -o $HOME/minio-binaries/kes
chmod +x $HOME/minio-binaries/kescurl -sSL --tlsv1.2 \
-O 'https://raw.githubusercontent.com/minio/kes/master/root.key' \
-O 'https://raw.githubusercontent.com/minio/kes/master/root.cert'
export KES_CLIENT_KEY=kms-identity/root.key
export KES_CLIENT_CERT=kms-identity/root.certexport KES_SERVER=https://play.min.io:7373kes key create dev-keyThis tutorial uses the example my-minio-sse-kms-key name for ease of reference. Specify a unique key name to prevent collision with existing keys. (e.g. dev-key)
Specify the following environment variables in the shell or terminal on each MinIO server host in the deployment (add in the ./docker/minio/docker-compose.yml)
export MINIO_KMS_KES_ENDPOINT=https://play.min.io:7373
export MINIO_KMS_KES_KEY_FILE=root.key
export MINIO_KMS_KES_CERT_FILE=root.cert
export MINIO_KMS_KES_KEY_NAME=dev-keymc admin service restart myminiomc encrypt set sse-kms dev-key myminio/testbucketNOTE: to remove automatic encryption on a bucket:
mc encrypt clear myminio/testbucketNOTE: And then leave this command hanging in a window to show output logs.
mc admin trace -v myminiokes identity new --ip "127.0.0.1" localhost --cert public.crt --key private.keyAPI Key (secret): kes:v1:AMZWKiawHEsCn30r9t8CV3MvdXVHQ6u4hJvu9q30X0iJ Identity: 6d2768043cc2350801ef0fbf9d5854541756841470fefe0d517067d1de5f426a
The identity can be computed again via:
kes identity of kes:v1:AMZWKiawHEsCn30r9t8CV3MvdXVHQ6u4hJvu9q30X0iJ
kes identity of public.crtkes identity new --key=client.key --cert=client.crt MyAppAPI Key (secret): kes:v1:AG8LgxNEBAL4aZZvDYzEDA4NKbyog5GMkpvrBgDyUCTr Identity: dfeef4d0a2b99cf65fb9ebe61275ae341643ef38cb108738d92ba94d36a81f6c
The identity can be computed again via:
kes identity of kes:v1:AG8LgxNEBAL4aZZvDYzEDA4NKbyog5GMkpvrBgDyUCTr
kes identity of client.crtNext, we can create the KES server configuration file: config.yml. Please, make sure that the identity in the policy section matches your client.crt identity.
address: 0.0.0.0:7373 # Listen on all network interfaces on port 7373
admin:
identity: dfeef4d0a2b99cf65fb9ebe61275ae341643ef38cb108738d92ba94d36a81f6c # The client.crt identity
tls:
key: private.key # The KES server TLS private key
cert: public.crt # The KES server TLS certificateNow, we can start a KES server instance:
kes server --config config.yml --auth offSource: https://github.com/minio/kes?tab=readme-ov-file#quick-start
- Configure CLI
export KES_SERVER=https://play.min.io:7373
export KES_API_KEY=kes:v1:AD9E7FSYWrMD+VjhI6q545cYT9YOyFxZb7UnjEepYDRc- Create a Key
kes key create my-key- Generate a DEK Derive a new Data Encryption Keys (DEK)
kes key dek my-keyFrom Project root:
cd scripts
./installMcAndKes.shthen set variables:
cd scripts
source setVars.shnow, check if commands are available
mc --help
kes --help