Skip to main content

Managing buckets

CDB Object Storage organizes files into buckets. The built-in file manager handles uploading and organizing files, with controls for public access and lifecycle policies.

Bucket creation

  1. 1

    Open the bucket list

    Navigate to the CDB Technical Web Portal > Storage > Object Storage and click the relevant storage name. Alternatively, open the storage's three-dot menu and select Buckets.

    Object Storage list with storage rows
  2. 2

    Click Add new bucket

    Bucket list with Add new bucket button
  3. 3

    Name the bucket

    In the dialog that appears, enter a name that meets the following criteria:

    • 3–63 characters.
    • Lowercase only.
    • No underscores, trailing dashes, consecutive dots, or a mix of dots and dashes — these conflict with DNS notation rules.
    • Unique across the entire CDB Object Storage system. A This bucket name already exists. Please use a different name error appears if the name is taken.
  4. 4

    Click Create

Avoid using sensitive information in the bucket name. The bucket name appears in object URLs and is publicly visible.

The new bucket appears in the list once created. The following sections cover how to upload and manage files, control public access, and configure lifecycle policies.

File manager

The file manager is a browser-based interface for managing files in a bucket. Two setup steps are required before use: configuring CORS and authenticating with S3 credentials.

CORS setup

To access the file manager, add https://portal.cdb-staging.cdn.orange.com to the bucket's CORS policy. This is a one-time setup per bucket.

Click the bucket name to open the access settings dialog, then click Override CORS.

Configure CORS individually for each bucket.
Override CORS dialog

The API also supports multiple allowed origins beyond https://portal.cdb-staging.cdn.orange.com.

Authorization

To authorize, click the bucket name, enter the Access key and Secret key, then click Auth.

Authorization form for the file manager

Alternatively, access the file manager from the bucket's three-dot menu by selecting File manager.

Adding folders

After authorizing, click Add folder. Enter a name in the field and click Create.

Add folder dialog

Each folder displays its last modification date. Click a folder name to open it.

Uploading files

To upload files, authorize and click Select and upload file(s) either in the bucket root or within a specific folder. Then, follow the standard upload process.

File manager with uploaded file and folder

Deleting folders and files

To delete folders or files, authorize and click Delete next to the desired object. Alternatively, select the checkboxes next to the object names and click Delete selected.

Delete confirmation dialog
Deleting a folder removes all files nested within it.

Copying file URLs

To copy file URLs, authorize, select objects, and click the relevant button: Copy S3 URL or Copy URL.

Copy S3 URL and Copy URL buttons visible for a selected file

The links for the file image 3972.png look like this:

  • s3://s-ed1.cloud.gcore.lu/000-sample-for-articles/test/image%203972.png
  • https://s-ed1.cloud.gcore.lu/000-sample-for-articles/test/image%203972.png
Without public HTTP access enabled, the direct file URL returns a 403 error.

Managing access

Enable public HTTP access to make files directly accessible by URL or to serve them through a CDN origin. Click the three-dot menu on the bucket row, select Public access to all files, and confirm by clicking Apply.

Confirmation dialog for enabling public HTTP access to all files in the bucket

To revert to private access, click the three-dot menu on the bucket row and click Default access to all files.

Confirmation dialog for reverting the bucket to default private access

Adding lifecycle policy (for S3 in Luxembourg only)

Click the three-dot menu on the bucket row and select Lifecycle Management. Set the retention period and click Save changes.

Lifecycle policy configuration dialog

To remove an existing policy, click Cancel policy.

For other storage locations, configure lifecycle policies with the AWS CLI.

Bucket operations within an S3 storage — creation, CORS rules, public access, and lifecycle policies — are managed through the buckets endpoint. Each request requires the numeric storage ID, returned when creating storage or available from the storage list.

An API token is required.

export GCORE_API_KEY="{YOUR_API_KEY}"
export STORAGE_ID="{YOUR_STORAGE_ID}"

Create bucket

Bucket names must be globally unique across the CDB Object Storage system, 3–63 lowercase characters, with no underscores, trailing dashes, consecutive dots, or combinations of dots and dashes.

ParameterRequiredDescription
nameYesGlobally unique bucket name, 3–63 lowercase characters
import os
from gcore import CDB

client = CDB()
storage_id = int(os.environ["STORAGE_ID"])

bucket = client.storage.object_storages.buckets.create(
    storage_id,
    name="my-bucket",
)
print(f"Bucket: {bucket.name}  storage_id={bucket.storage_id}")
package main

import (
    "context"
    "fmt"
    "log"
    "os"
    "strconv"

    gcore "github.com/G-Core/gcore-go"
    "github.com/G-Core/gcore-go/storage"
)

func main() {
    storageID, _ := strconv.ParseInt(os.Getenv("STORAGE_ID"), 10, 64)

    client := gcore.NewClient()
    ctx := context.Background()

    bucket, err := client.Storage.ObjectStorages.Buckets.New(ctx, storageID, storage.ObjectStorageBucketNewParams{
        Name: "my-bucket",
    })
    if err != nil {
        log.Fatalf("create bucket: %v", err)
    }
    fmt.Printf("Bucket: %s  storage_id=%d\n", bucket.Name, bucket.StorageID)
}
curl -X POST "https://api.cdb-staging.cdn.orange.com/storage/v4/object_storages/$STORAGE_ID/buckets" \
  -H "Authorization: APIKey $GCORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "my-bucket"}'

The API returns:

{
  "name": "my-bucket",
  "storage_id": 13799,
  "cors": null,
  "lifecycle": null,
  "policy": null
}

List buckets

Returns all buckets in a storage, including their current CORS, lifecycle, and public access settings.

import os
from gcore import CDB

client = CDB()
storage_id = int(os.environ["STORAGE_ID"])

buckets = client.storage.object_storages.buckets.list(storage_id)
for b in buckets:
    print(f"{b.name}  is_public={b.policy.is_public if b.policy else False}")
package main

import (
    "context"
    "fmt"
    "log"
    "os"
    "strconv"

    gcore "github.com/G-Core/gcore-go"
    "github.com/G-Core/gcore-go/storage"
)

func main() {
    storageID, _ := strconv.ParseInt(os.Getenv("STORAGE_ID"), 10, 64)

    client := gcore.NewClient()
    ctx := context.Background()

    page, err := client.Storage.ObjectStorages.Buckets.List(ctx, storageID, storage.ObjectStorageBucketListParams{})
    if err != nil {
        log.Fatalf("list buckets: %v", err)
    }
    for _, b := range page.Results {
        fmt.Printf("%s  is_public=%v\n", b.Name, b.Policy.IsPublic)
    }
}
curl "https://api.cdb-staging.cdn.orange.com/storage/v4/object_storages/$STORAGE_ID/buckets" \
  -H "Authorization: APIKey $GCORE_API_KEY"

The API returns:

{
  "count": 2,
  "results": [
    {
      "name": "my-bucket",
      "storage_id": 13799,
      "cors": {
        "allowed_origins": ["https://portal.cdb-staging.cdn.orange.com"]
      },
      "lifecycle": null,
      "policy": {
        "is_public": false
      }
    },
    {
      "name": "my-other-bucket",
      "storage_id": 13799,
      "cors": null,
      "lifecycle": {
        "expiration_days": 30
      },
      "policy": {
        "is_public": true
      }
    }
  ]
}

Configure CORS

CORS rules control which web origins can make direct browser requests to the bucket. Sending an empty array removes all CORS rules.

ParameterRequiredDescription
cors.allowed_originsYesList of allowed origin URLs, e.g. ["https://portal.cdb-staging.cdn.orange.com"]. Send [] to remove CORS.
import os
from gcore import CDB

client = CDB()
storage_id = int(os.environ["STORAGE_ID"])

bucket = client.storage.object_storages.buckets.update(
    "my-bucket",
    storage_id=storage_id,
    cors={"allowed_origins": ["https://portal.cdb-staging.cdn.orange.com", "https://example.com"]},
)
print(f"Allowed origins: {bucket.cors.allowed_origins}")
package main

import (
    "context"
    "fmt"
    "log"
    "os"
    "strconv"

    gcore "github.com/G-Core/gcore-go"
    "github.com/G-Core/gcore-go/storage"
)

func main() {
    storageID, _ := strconv.ParseInt(os.Getenv("STORAGE_ID"), 10, 64)

    client := gcore.NewClient()
    ctx := context.Background()

    bucket, err := client.Storage.ObjectStorages.Buckets.Update(ctx, "my-bucket", storage.ObjectStorageBucketUpdateParams{
        StorageID: storageID,
        Cors: storage.ObjectStorageBucketUpdateParamsCors{
            AllowedOrigins: []string{"https://portal.cdb-staging.cdn.orange.com", "https://example.com"},
        },
    })
    if err != nil {
        log.Fatalf("update CORS: %v", err)
    }
    fmt.Printf("Allowed origins: %v\n", bucket.Cors.AllowedOrigins)
}
curl -X PATCH "https://api.cdb-staging.cdn.orange.com/storage/v4/object_storages/$STORAGE_ID/buckets/my-bucket" \
  -H "Authorization: APIKey $GCORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"cors": {"allowed_origins": ["https://portal.cdb-staging.cdn.orange.com", "https://example.com"]}}'

The API returns the updated bucket object with cors.allowed_origins set.

Enable or disable public access

Setting is_public to true allows unauthenticated downloads of all objects in the bucket by direct URL. Set to false to require S3 credentials for all requests.

import os
from gcore import CDB

client = CDB()
storage_id = int(os.environ["STORAGE_ID"])

# Enable public access
bucket = client.storage.object_storages.buckets.update(
    "my-bucket",
    storage_id=storage_id,
    policy={"is_public": True},
)
print(f"is_public={bucket.policy.is_public}")

# Revert to private
bucket = client.storage.object_storages.buckets.update(
    "my-bucket",
    storage_id=storage_id,
    policy={"is_public": False},
)
print(f"is_public={bucket.policy.is_public}")
package main

import (
    "context"
    "fmt"
    "log"
    "os"
    "strconv"

    gcore "github.com/G-Core/gcore-go"
    "github.com/G-Core/gcore-go/packages/param"
    "github.com/G-Core/gcore-go/storage"
)

func main() {
    storageID, _ := strconv.ParseInt(os.Getenv("STORAGE_ID"), 10, 64)

    client := gcore.NewClient()
    ctx := context.Background()

    // Enable public access
    bucket, err := client.Storage.ObjectStorages.Buckets.Update(ctx, "my-bucket", storage.ObjectStorageBucketUpdateParams{
        StorageID: storageID,
        Policy: storage.ObjectStorageBucketUpdateParamsPolicy{
            IsPublic: param.NewOpt[bool](true),
        },
    })
    if err != nil {
        log.Fatalf("enable public access: %v", err)
    }
    fmt.Printf("is_public=%v\n", bucket.Policy.IsPublic)
}
# Enable public access
curl -X PATCH "https://api.cdb-staging.cdn.orange.com/storage/v4/object_storages/$STORAGE_ID/buckets/my-bucket" \
  -H "Authorization: APIKey $GCORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"policy": {"is_public": true}}'

# Revert to private
curl -X PATCH "https://api.cdb-staging.cdn.orange.com/storage/v4/object_storages/$STORAGE_ID/buckets/my-bucket" \
  -H "Authorization: APIKey $GCORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"policy": {"is_public": false}}'

The API returns the updated bucket object with policy.is_public reflecting the new value.

Set lifecycle policy

Lifecycle policies automatically delete objects after a set number of days. This feature is available for S3 storage in Luxembourg only. Set expiration_days to a positive integer to enable, or to 0 to remove an existing policy.

ParameterRequiredDescription
lifecycle.expiration_daysYesDays before objects are deleted. Use 0 to remove the rule.
import os
from gcore import CDB

client = CDB()
storage_id = int(os.environ["STORAGE_ID"])

# Set 30-day expiration
bucket = client.storage.object_storages.buckets.update(
    "my-bucket",
    storage_id=storage_id,
    lifecycle={"expiration_days": 30},
)
print(f"expiration_days={bucket.lifecycle.expiration_days}")

# Remove the lifecycle policy
bucket = client.storage.object_storages.buckets.update(
    "my-bucket",
    storage_id=storage_id,
    lifecycle={"expiration_days": 0},
)
print(f"lifecycle={bucket.lifecycle}")  # None
package main

import (
    "context"
    "fmt"
    "log"
    "os"
    "strconv"

    gcore "github.com/G-Core/gcore-go"
    "github.com/G-Core/gcore-go/packages/param"
    "github.com/G-Core/gcore-go/storage"
)

func main() {
    storageID, _ := strconv.ParseInt(os.Getenv("STORAGE_ID"), 10, 64)

    client := gcore.NewClient()
    ctx := context.Background()

    // Set 30-day expiration
    bucket, err := client.Storage.ObjectStorages.Buckets.Update(ctx, "my-bucket", storage.ObjectStorageBucketUpdateParams{
        StorageID: storageID,
        Lifecycle: storage.ObjectStorageBucketUpdateParamsLifecycle{
            ExpirationDays: param.NewOpt[int64](30),
        },
    })
    if err != nil {
        log.Fatalf("set lifecycle: %v", err)
    }
    fmt.Printf("expiration_days=%d\n", bucket.Lifecycle.ExpirationDays)

    // Remove the lifecycle policy
    bucket, err = client.Storage.ObjectStorages.Buckets.Update(ctx, "my-bucket", storage.ObjectStorageBucketUpdateParams{
        StorageID: storageID,
        Lifecycle: storage.ObjectStorageBucketUpdateParamsLifecycle{
            ExpirationDays: param.NewOpt[int64](0),
        },
    })
    if err != nil {
        log.Fatalf("remove lifecycle: %v", err)
    }
    fmt.Printf("lifecycle removed: expiration_days=%d\n", bucket.Lifecycle.ExpirationDays)
}
# Set 30-day expiration
curl -X PATCH "https://api.cdb-staging.cdn.orange.com/storage/v4/object_storages/$STORAGE_ID/buckets/my-bucket" \
  -H "Authorization: APIKey $GCORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"lifecycle": {"expiration_days": 30}}'

# Remove the lifecycle policy
curl -X PATCH "https://api.cdb-staging.cdn.orange.com/storage/v4/object_storages/$STORAGE_ID/buckets/my-bucket" \
  -H "Authorization: APIKey $GCORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"lifecycle": {"expiration_days": 0}}'

The API returns the updated bucket object. When the policy is removed, lifecycle is null.

Delete bucket

Deleting a bucket permanently removes it and all objects it contains. The bucket name becomes available again after deletion.

import os
from gcore import CDB

client = CDB()
storage_id = int(os.environ["STORAGE_ID"])

client.storage.object_storages.buckets.delete("my-bucket", storage_id=storage_id)
print("Bucket deleted")
package main

import (
    "context"
    "fmt"
    "log"
    "os"
    "strconv"

    gcore "github.com/G-Core/gcore-go"
    "github.com/G-Core/gcore-go/storage"
)

func main() {
    storageID, _ := strconv.ParseInt(os.Getenv("STORAGE_ID"), 10, 64)

    client := gcore.NewClient()
    ctx := context.Background()

    err := client.Storage.ObjectStorages.Buckets.Delete(ctx, "my-bucket", storage.ObjectStorageBucketDeleteParams{
        StorageID: storageID,
    })
    if err != nil {
        log.Fatalf("delete bucket: %v", err)
    }
    fmt.Println("Bucket deleted")
}
curl -X DELETE "https://api.cdb-staging.cdn.orange.com/storage/v4/object_storages/$STORAGE_ID/buckets/my-bucket" \
  -H "Authorization: APIKey $GCORE_API_KEY"

Returns HTTP 204 with no response body.

Declare S3 buckets with CORS rules, public access policy, and lifecycle settings using the CDB Terraform provider v2.

Create bucket

Declares a bucket in an existing S3 storage. CORS rules, public access, and lifecycle policy are optional — omit any block to leave that setting unconfigured.

resource "gcore_storage_object_storage_bucket" "example" {
  storage_id = var.storage_id
  name       = "my-bucket"

  cors = {
    allowed_origins = ["https://portal.cdb-staging.cdn.orange.com"]
  }

  policy = {
    is_public = false
  }

  storage_object_storage_bucket_lifecycle = {
    expiration_days = 30
  }
}

variable "storage_id" {
  type = number
}
terraform apply

Update bucket settings

Edit any field in the resource block and run terraform apply. To remove the lifecycle policy, omit the storage_object_storage_bucket_lifecycle attribute.

resource "gcore_storage_object_storage_bucket" "example" {
  storage_id = var.storage_id
  name       = "my-bucket"

  cors = {
    allowed_origins = ["https://portal.cdb-staging.cdn.orange.com", "https://example.com"]
  }

  policy = {
    is_public = true
  }

  # Omit storage_object_storage_bucket_lifecycle to remove the lifecycle policy
}
terraform apply

Delete bucket

Remove the resource block — Terraform deletes the bucket and all its objects on the next apply.

# Remove or comment out this block:
# resource "gcore_storage_object_storage_bucket" "example" {
#   storage_id = var.storage_id
#   name       = "my-bucket"
# }
terraform apply