Skip to main content

Manage S3 access keys

S3 access keys authenticate AWS CLI, SDKs, and other S3-compatible clients. An S3 storage is required before keys can be created.

S3 Standard storage holds up to 10 keys, and S3 Fast storage holds up to two keys. If the storage has an available key slot, create a replacement key, update applications, then delete the old key to rotate credentials without downtime.

Read-only keys can list and download objects, but cannot upload, overwrite, or delete them, and cannot create or delete buckets. They are supported on S3 Standard only, and permissions are fixed at creation, so delete a key and create another to change access.

  1. 1

    Open Access keys

    In the CDB Technical Web Portal, navigate to Storage > Object Storages. Click ... next to the storage name and select Access keys.

  2. 2

    Create a key

    On S3 Standard, click Create read-write key or Create read-only key, while S3 Fast shows Create read-write key only. The dialog shows the access key and secret key. Click Copy credentials and store both values, because the secret is shown only once.

    The list shows Access key, Permissions, and Created for each key.

    Access keys dialog with read-write and read-only keys
  3. 3

    Delete a key

    Click the delete control next to the key. Create a replacement and update clients before deleting a key that is still in use.

Access keys are created and deleted on an existing S3 storage, and the numeric storage ID is returned when creating storage or from the storage list. The secret key is returned only in the create response.

An API token is required.

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

Key creation

An empty POST body creates a read-write key, and the response sets read_only to false. A JSON body with read_only set to true creates a read-only key on S3 Standard storage. Key permissions cannot be changed after creation. To change access, create a replacement key and delete the old one.

The following examples create access keys. Read-only keys are supported on S3 Standard only.

from gcore import CDB

client = CDB()

storage_id = 13864

new_key = client.storage.object_storages.access_keys.create(storage_id)
print(f"New access key: {new_key.access_key}")
print(f"New secret key: {new_key.secret_key}")

# Read-only keys are supported on S3 Standard only
ro_key = client.storage.object_storages.access_keys.create(
    storage_id,
    extra_body={"read_only": True},
)
print(f"Read-only access key: {ro_key.access_key}")
print(f"Read-only secret key: {ro_key.secret_key}")
package main

import (
    "context"
    "fmt"
    "log"

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

func main() {
    client := gcore.NewClient()
    ctx := context.Background()

    var storageID int64 = 13864

    newKey, err := client.Storage.ObjectStorages.AccessKeys.New(ctx, storageID)
    if err != nil {
        log.Fatalf("create access key: %v", err)
    }
    fmt.Printf("New access key: %s\n", newKey.AccessKey)
    fmt.Printf("New secret key: %s\n", newKey.SecretKey)
}
curl -X POST "https://api.cdb-staging.cdn.orange.com/storage/v4/object_storages/$STORAGE_ID/access_keys" \
  -H "Authorization: APIKey $GCORE_API_KEY"

Response:

{
  "access_key": "0CW9Q09ART50W9XB4O13",
  "secret_key": "oO5jztJ4ewahrFGX9pMNIq0X3nfVVlfu9XVO9NLz",
  "created_at": "2026-07-13T13:07:54Z",
  "read_only": false
}

Read-only key on S3 Standard:

curl -X POST "https://api.cdb-staging.cdn.orange.com/storage/v4/object_storages/$STORAGE_ID/access_keys" \
  -H "Authorization: APIKey $GCORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"read_only": true}'

Response:

{
  "access_key": "0CW9Q09ART50W9XB4O13",
  "secret_key": "oO5jztJ4ewahrFGX9pMNIq0X3nfVVlfu9XVO9NLz",
  "created_at": "2026-07-13T13:07:54Z",
  "read_only": true
}

S3 Fast returns HTTP 400, because read-only keys are supported on S3 Standard only. The error body uses CEPH for S3 Standard:

{"error":"read-only access keys are only supported for CEPH storages"}

When the limit is reached, the API returns HTTP 409:

{"error":"maximum number of access keys reached"}

Key deletion

Delete an access key after updating all clients to the remaining credentials. The same request deletes read-write and read-only keys.

from gcore import CDB

client = CDB()

storage_id = 13864
old_access_key = "L1M3FSX3T0B3TWDVINKT"

client.storage.object_storages.access_keys.delete(old_access_key, storage_id=storage_id)
print("Old access key deleted")
package main

import (
    "context"
    "fmt"
    "log"

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

func main() {
    client := gcore.NewClient()
    ctx := context.Background()

    var storageID int64 = 13864
    oldAccessKey := "L1M3FSX3T0B3TWDVINKT"

    err := client.Storage.ObjectStorages.AccessKeys.Delete(ctx, oldAccessKey, storage.ObjectStorageAccessKeyDeleteParams{
        StorageID: storageID,
    })
    if err != nil {
        log.Fatalf("delete access key: %v", err)
    }
    fmt.Println("Old access key deleted")
}
export OLD_ACCESS_KEY="{OLD_ACCESS_KEY}"

curl -X DELETE "https://api.cdb-staging.cdn.orange.com/storage/v4/object_storages/$STORAGE_ID/access_keys/$OLD_ACCESS_KEY" \
  -H "Authorization: APIKey $GCORE_API_KEY"

Returns HTTP 204 with no response body.

Create additional S3 access keys on an existing storage with the CDB Terraform provider v2. gcore_storage_access_key creates a read-write key, and the storage already has one key from provisioning.

Additional key

Declare gcore_storage_access_key with the storage ID. Apply creates the key, and the secret is available in Terraform state.

resource "gcore_storage_access_key" "extra" {
  storage_id = gcore_storage_object_storage.example.id
}

output "extra_access_key" {
  value = gcore_storage_access_key.extra.access_key
}

output "extra_secret_key" {
  value     = gcore_storage_access_key.extra.secret_key
  sensitive = true
}
terraform apply

Key rotation

This rotation applies only to additional keys declared as gcore_storage_access_key. The key created when the storage is provisioned belongs to gcore_storage_object_storage and is not deleted by removing an access key resource. Declare a new gcore_storage_access_key, update clients to the new credentials, then remove the resource block for the previous Terraform-managed key and apply.

# Add a new key resource, update clients, then remove this block:
# resource "gcore_storage_access_key" "extra" {
#   storage_id = gcore_storage_object_storage.example.id
# }
terraform apply