data-vault/scripts/collection/cloudflare_tools.py
2025-02-26 14:49:24 -05:00

94 lines
3.8 KiB
Python

import logging
from pathlib import Path
import click
from cloudflare import Cloudflare
import os
from scripts.helpers.misc import load_config
logger = logging.getLogger(__name__)
def generate_temp_key(account_id: str, bucket: str, parent_access_key_id: str, token: str,
permission: str = "object-read-write", ttl_seconds: int = 3600,
prefixes: list[str] | None = None, objects: list[str] | None = None):
"""Generate a temporary R2 access key using the Cloudflare API.
Args:
account_id: Cloudflare account ID
bucket: R2 bucket name
parent_access_key_id: Parent access key ID
token: Cloudflare API token
permission: Permission level ('object-read-write' or 'object-read')
ttl_seconds: Time-to-live in seconds
prefixes: Optional list of key prefixes to restrict access to
objects: Optional list of specific object keys to restrict access to
"""
params = {
"account_id": account_id,
"bucket": bucket,
"parent_access_key_id": parent_access_key_id,
"permission": permission,
"ttl_seconds": ttl_seconds,
}
if prefixes:
params["prefixes"] = prefixes
if objects:
params["objects"] = objects
return Cloudflare(api_token=token).r2.temporary_credentials.create(**params)
@click.group()
def cli():
"""Cloudflare R2 utility commands."""
pass
@cli.command()
@click.option('--bucket', '-b', type=str, required=True,
help='R2 bucket name.')
@click.option('--permission', '-p', type=click.Choice(['object-read-write', 'object-read']),
default='object-read-write',
help='Permission level for the temporary key.')
@click.option('--ttl', '-t', type=int, default=1,
help='Time-to-live in hours for the temporary key.')
@click.option('--prefixes', '-x', multiple=True,
help='Key prefixes to restrict access to. Can be specified multiple times.')
@click.option('--objects', '-o', multiple=True,
help='Specific object keys to restrict access to. Can be specified multiple times.')
def generate_key(bucket: str, permission: str, ttl: int, prefixes: tuple[str, ...],
objects: tuple[str, ...], log_level: str):
"""Generate temporary Cloudflare R2 access credentials."""
# Load config
config = load_config().get("temp_tokens", {})
if not config or any(key not in config for key in ['parent_access_key_id', 'account_id', 'token']):
raise click.ClickException("Config file must have 'temp_tokens' dict with 'parent_access_key_id', 'account_id', and 'token' keys")
# Generate temporary key
temp_cred = generate_temp_key(
account_id=config['account_id'],
bucket=bucket,
parent_access_key_id=config['parent_access_key_id'],
token=config['token'],
permission=permission,
ttl_seconds=ttl * 3600,
prefixes=list(prefixes) if prefixes else None,
objects=list(objects) if objects else None
)
# Output AWS config format
click.echo("\n# Add this to ~/.aws/config:")
click.echo("[profile r2-temp]")
click.echo(f"aws_access_key_id = {temp_cred.access_key_id}")
click.echo(f"aws_secret_access_key = {temp_cred.secret_access_key}")
click.echo(f"aws_session_token = {temp_cred.session_token}")
click.echo("region = auto")
click.echo(f"endpoint_url = https://{config['account_id']}.r2.cloudflarestorage.com")
# Output sample command using first prefix if available
click.echo("\n# Sample upload command:")
sample_path = objects[0] if objects else f"{prefixes[0].strip('/')}/" if prefixes else ""
click.echo(f"aws s3 cp local-file.txt s3://{bucket}/{sample_path} --profile r2-temp")
if __name__ == "__main__":
cli()