Leaseweb Object Storage com Tofu

Um how-to de como fazer a gestão do object storage da Leaseweb com OpenTofu, incluindo politicas de ciclo de vida.

O Object Storage da Leaseweb é uma das alternativas Europeias ao famoso S3 da AWS. Porém, o dashboard apenas permite fazer a gestão de utilizadores e grupos (aqui ainda é possível definir politicas de acesso), tudo o resto tem que ser feito com uma ferramenta externa.

Leaseweb Object Storage Dashboard

Ora, sendo compatível com o S3, nós podemos usar o OpenTofu (ou o Terraform) com o provider da AWS para fazer gestão dos nossos bucket, permissões e ciclo de vida. Bora lá.

Provider

Para usar o provider da AWS, precisamos de fazer as seguintes alterações:

  • Definir a região1
  • Desativar o STS1
  • Forçar o URL do S3
  • Desativar a verificação da região

A nossa configuração do provider fica então assim:

 1provider "aws" {
 2  region     = "nl-01"
 3  access_key = var.s3_access_key
 4  secret_key = var.s3_secret_key
 5
 6  # LSW implementation has no STS service
 7  skip_credentials_validation = true
 8  skip_requesting_account_id  = true
 9  # the AWS region is unknown to AWS hence skipping is needed.
10  skip_region_validation = true
11  endpoints {
12    s3 = "https://nl.object-storage.io"
13  }
14}

Recursos

O bucket e respetiva politica de acessos não difere do uso normal com o S3 da AWS.

 1resource "aws_s3_bucket" "this" {
 2  bucket_prefix = "my-awesome-bucket-"
 3}
 4
 5resource "aws_s3_bucket_policy" "this" {
 6  bucket = aws_s3_bucket.this.id
 7  policy = jsonencode({
 8    Statement = [
 9      {
10        Action    = [
11          "s3:*"
12        ]
13        Effect    = "Allow"
14        Principal = {
15          AWS = ["arn:aws:iam::00000000000000000000:user/my-user"]
16        }
17        Resource  = ["arn:aws:s3:::${aws_s3_bucket.this.id}/*"]
18       }
19     ]
20   })
21}

A politica do ciclo de vida, essa sim já é diferente. Precisamos de forçar a opção transition_default_minimum_object_size para uma string vazia. Isto acontece porque a Leaseweb apenas tem uma storage class.

 1resource "aws_s3_bucket_lifecycle_configuration" "this" {
 2  bucket = aws_s3_bucket.this.id
 3
 4  # LSW needs this in order for tofu to work
 5  transition_default_minimum_object_size = ""
 6  rule {
 7    id = "daily"
 8    filter {
 9      tag {
10        key = "retention"
11        value = "daily"
12      }
13    }
14
15    expiration {
16      days = 30
17    }
18
19    status = "Enabled"
20  }
21
22}

ARN

Como a Leaseweb não suporta STS, não conseguimos obter o ID da nossa conta via Tofu. Eu obti o meu através do S3 Manager.

S3 Manager object listing

Exemplo completo

 1variable "s3_access_key" {
 2  type = string
 3  description = "S3 Access Key"
 4  sensitive = true
 5}
 6
 7variable "s3_secret_key" {
 8  type = string
 9  description = "S3 Secret Key"
10  sensitive = true
11}
12
13
14provider "aws" {
15  region     = "nl-01"
16  access_key = var.s3_access_key
17  secret_key = var.s3_secret_key
18
19  # LSW implementation has no STS service
20  skip_credentials_validation = true
21  skip_requesting_account_id  = true
22  # the AWS region is unknown to AWS hence skipping is needed.
23  skip_region_validation = true
24  endpoints {
25    s3 = "https://nl.object-storage.io"
26  }
27}
28
29resource "aws_s3_bucket" "this" {
30  bucket_prefix = "my-awesome-bucket-"
31}
32
33resource "aws_s3_bucket_policy" "this" {
34  bucket = aws_s3_bucket.this.id
35  policy = jsonencode({
36    Statement = [
37      {
38        Action    = [
39          "s3:*"
40        ]
41        Effect    = "Allow"
42        Principal = {
43          AWS = ["arn:aws:iam::00000000000000000000:user/my-user"]
44        }
45        Resource  = ["arn:aws:s3:::${aws_s3_bucket.this.id}/*"]
46       }
47     ]
48   })
49}
50
51resource "aws_s3_bucket_lifecycle_configuration" "this" {
52  bucket = aws_s3_bucket.this.id
53
54  # LSW needs this in order for tofu to work
55  transition_default_minimum_object_size = ""
56  rule {
57    id = "daily"
58    filter {
59      tag {
60        key = "retention"
61        value = "daily"
62      }
63    }
64
65    expiration {
66      days = 30
67    }
68
69    status = "Enabled"
70  }
71
72}