orbital

module
v0.0.0-...-53d592e Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 27, 2026 License: GPL-3.0

README ΒΆ

πŸͺ Orbital - AWS S3 Bucket Kubernetes Operator

License Go Report Card Kubernetes

A production-grade Kubernetes operator for managing AWS S3 buckets declaratively using Custom Resource Definitions (CRDs). Built with Kubebuilder, Orbital enables GitOps-friendly S3 bucket management with lifecycle policies, versioning, and secure credential management.

✨ Features

  • Declarative Management: Define S3 buckets as Kubernetes resources
  • Lifecycle Policies: Automatic bucket deletion after specified days (1-3650 days)
  • Versioning Support: Enable/disable S3 bucket versioning
  • Secure Credentials: AWS credentials stored in Kubernetes Secrets
  • Deletion Policies: Choose between Delete or Retain on CR deletion
  • Status Tracking: Real-time bucket status with conditions and timestamps
  • Production Ready: Finalizers, leader election, metrics, and health checks
  • GitOps Compatible: Fully compatible with ArgoCD, Flux, and other GitOps tools

πŸ“‹ Table of Contents

πŸ—οΈ Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    Kubernetes Cluster                        β”‚
β”‚                                                              β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                                       β”‚
β”‚  β”‚   S3Bucket CR    β”‚                                       β”‚
β”‚  β”‚  (Desired State) β”‚                                       β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                                       β”‚
β”‚           β”‚                                                  β”‚
β”‚           β”‚ Watch & Reconcile                               β”‚
β”‚           β–Ό                                                  β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                  β”‚
β”‚  β”‚   Orbital Controller                  β”‚                  β”‚
β”‚  β”‚                                       β”‚                  β”‚
β”‚  β”‚  1. Fetch CR                         β”‚                  β”‚
β”‚  β”‚  2. Get AWS Credentials (Secret)     β”‚                  β”‚
β”‚  β”‚  3. Check Lifecycle Policy           β”‚                  β”‚
β”‚  β”‚  4. Reconcile with AWS               β”‚                  β”‚
β”‚  β”‚  5. Update Status                    β”‚                  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                  β”‚
β”‚           β”‚                                                  β”‚
β”‚           β”‚ AWS SDK Calls                                   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
            β”‚
            β”‚ HTTPS
            β–Ό
   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
   β”‚     AWS S3 API     β”‚
   β”‚                    β”‚
   β”‚  - CreateBucket    β”‚
   β”‚  - DeleteBucket    β”‚
   β”‚  - PutVersioning   β”‚
   β”‚  - HeadBucket      β”‚
   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
Reconciliation Flow
graph TD
    A[S3Bucket CR Applied] --> B{CR Deleted?}
    B -->|Yes| C{Has Finalizer?}
    C -->|Yes| D{DeletionPolicy?}
    D -->|Delete| E[Delete S3 Bucket]
    D -->|Retain| F[Skip Deletion]
    E --> G[Remove Finalizer]
    F --> G
    G --> H[End]
    
    B -->|No| I{Has Finalizer?}
    I -->|No| J[Add Finalizer]
    J --> K[Requeue]
    
    I -->|Yes| L[Get AWS Credentials from Secret]
    L --> M[Initialize S3 Client]
    M --> N[Ensure Bucket Exists]
    N --> O[Configure Versioning]
    O --> P{Lifecycle Policy Set?}
    P -->|Yes| Q{Creation Time Set?}
    Q -->|No| R[Set Creation Time]
    R --> S[Calculate Deletion Time]
    S --> T{Time to Delete?}
    T -->|Yes| U[Delete Bucket]
    U --> V[Delete CR]
    T -->|No| W[Update Status: Ready]
    W --> X[Requeue Before Deletion]
    
    P -->|No| Y[Update Status: Ready]
    Q -->|Yes| T
    Y --> H
    X --> H

πŸš€ Quick Start

Prerequisites
  • Kubernetes cluster (v1.30+)
  • kubectl configured
  • AWS account with S3 permissions
  • Helm 3.0+ (for Helm installation)
Install with Helm
# Add the Helm repository (if published)
helm repo add orbital https://raihankhan.github.io/orbital
helm repo update

# Install the operator
helm install orbital orbital/orbital \
  -n orbital-system \
  --create-namespace

# Or install from local chart
helm install orbital ./helm/orbital \
  -n orbital-system \
  --create-namespace
Create AWS Credentials Secret
kubectl create secret generic orbital-aws-creds \
  --from-literal=AWS_ACCESS_KEY_ID=<your-access-key-id> \
  --from-literal=AWS_SECRET_ACCESS_KEY=<your-secret-access-key> \
  -n default
Create Your First S3 Bucket
apiVersion: infra.orbital.dev/v1alpha1
kind: S3Bucket
metadata:
  name: my-app-bucket
spec:
  bucketName: my-unique-app-bucket-12345
  region: us-east-1
  versioning: true
  deletionPolicy: Delete
  awsSecretRef:
    name: orbital-aws-creds
    namespace: default
  lifecycle:
    deleteAfterDays: 90  # Optional: auto-delete after 90 days
kubectl apply -f my-bucket.yaml
kubectl get s3buckets
kubectl describe s3bucket my-app-bucket

πŸ“¦ Installation

See Quick Start above.

Option 2: Manual Installation with Kustomize
# Install CRDs
make install

# Deploy the controller
make deploy IMG=ghcr.io/raihankhan/orbital:v0.1.0
Option 3: Local Development
# Run locally (requires AWS credentials in environment or ~/.aws/credentials)
make run

πŸ“– API Reference

S3BucketSpec
Field Type Required Description
bucketName string Yes Unique S3 bucket name (3-63 chars, DNS-compliant)
region string Yes AWS region (us-east-1, us-west-2, ap-south-1, eu-central-1)
versioning bool No Enable S3 bucket versioning (default: false)
deletionPolicy string No Delete or Retain (default: Delete)
awsSecretRef SecretReference No Reference to Secret with AWS credentials
lifecycle.deleteAfterDays int32 No Auto-delete bucket after N days (1-3650)
S3BucketStatus
Field Type Description
phase string Current phase: Pending, Ready, Error, Deleted
observedGeneration int64 Last observed generation of the spec
conditions []Condition Standard Kubernetes conditions
creationTime Time Timestamp when bucket was created
scheduledDeletionTime Time When bucket is scheduled for lifecycle deletion
Conditions
Type Status Reason Description
Ready True Ready Bucket successfully synchronized
Ready False Error Reconciliation failed

πŸ’‘ Usage Examples

Example 1: Simple Bucket
apiVersion: infra.orbital.dev/v1alpha1
kind: S3Bucket
metadata:
  name: simple-bucket
spec:
  bucketName: my-simple-bucket
  region: us-east-1
  awsSecretRef:
    name: orbital-aws-creds
    namespace: default
Example 2: Versioned Bucket with Retention
apiVersion: infra.orbital.dev/v1alpha1
kind: S3Bucket
metadata:
  name: versioned-bucket
spec:
  bucketName: my-versioned-bucket
  region: us-west-2
  versioning: true
  deletionPolicy: Retain  # Keep bucket when CR is deleted
  awsSecretRef:
    name: orbital-aws-creds
    namespace: default
Example 3: Temporary Bucket with Lifecycle
apiVersion: infra.orbital.dev/v1alpha1
kind: S3Bucket
metadata:
  name: temp-bucket
spec:
  bucketName: my-temp-bucket
  region: ap-south-1
  versioning: false
  deletionPolicy: Delete
  lifecycle:
    deleteAfterDays: 7  # Auto-delete after 7 days
  awsSecretRef:
    name: orbital-aws-creds
    namespace: default

🏭 Production Use Cases

Use Case 1: Multi-Tenant Application Storage

Scenario: SaaS application needs isolated S3 buckets per tenant with automatic cleanup.

apiVersion: infra.orbital.dev/v1alpha1
kind: S3Bucket
metadata:
  name: tenant-acme-storage
  namespace: tenant-acme
  labels:
    tenant: acme
    app: storage
spec:
  bucketName: prod-tenant-acme-storage
  region: us-east-1
  versioning: true
  deletionPolicy: Retain  # Prevent accidental deletion
  awsSecretRef:
    name: s3-credentials
    namespace: tenant-acme

Benefits:

  • Declarative per-tenant bucket provisioning
  • GitOps-friendly tenant onboarding
  • Automatic bucket creation via CI/CD
  • Namespace isolation for credentials
Use Case 2: Temporary Data Processing Buckets

Scenario: Data pipeline creates temporary buckets for batch jobs that should auto-cleanup.

apiVersion: infra.orbital.dev/v1alpha1
kind: S3Bucket
metadata:
  name: batch-job-20260127
  labels:
    job-id: "20260127"
    type: temporary
spec:
  bucketName: batch-processing-20260127-abc123
  region: us-west-2
  versioning: false
  deletionPolicy: Delete
  lifecycle:
    deleteAfterDays: 30  # Auto-cleanup after 30 days
  awsSecretRef:
    name: batch-job-credentials
    namespace: data-pipeline

Benefits:

  • Automatic cleanup prevents storage cost accumulation
  • No manual intervention required
  • Audit trail via Kubernetes events
  • Cost optimization through lifecycle policies
Use Case 3: Disaster Recovery with Versioning

Scenario: Critical application data requires versioning and retention policies.

apiVersion: infra.orbital.dev/v1alpha1
kind: S3Bucket
metadata:
  name: app-backup-primary
  namespace: production
  annotations:
    backup.policy: "daily"
    retention.days: "365"
spec:
  bucketName: prod-app-backup-primary-us-east-1
  region: us-east-1
  versioning: true  # Enable versioning for point-in-time recovery
  deletionPolicy: Retain  # Never delete on CR removal
  awsSecretRef:
    name: backup-s3-credentials
    namespace: production
---
apiVersion: infra.orbital.dev/v1alpha1
kind: S3Bucket
metadata:
  name: app-backup-dr
  namespace: production
spec:
  bucketName: prod-app-backup-dr-us-west-2
  region: us-west-2  # Different region for DR
  versioning: true
  deletionPolicy: Retain
  awsSecretRef:
    name: backup-s3-credentials
    namespace: production

Benefits:

  • Infrastructure as Code for disaster recovery
  • Consistent configuration across regions
  • Version control for bucket definitions
  • Automated DR bucket provisioning

πŸ› οΈ Local Development

Prerequisites
  • Go 1.25+
  • Docker
  • kubectl
  • Kubebuilder 4.11+
  • AWS CLI configured (for testing)
Setup Development Environment
# Clone the repository
git clone https://github.com/raihankhan/orbital.git
cd orbital

# Install dependencies
go mod download

# Generate CRDs and code
make manifests generate

# Run tests
make test

# Run locally (connects to your current kubectl context)
make run
Project Structure
orbital/
β”œβ”€β”€ api/v1alpha1/          # CRD definitions
β”‚   β”œβ”€β”€ s3bucket_types.go
β”‚   └── groupversion_info.go
β”œβ”€β”€ internal/
β”‚   β”œβ”€β”€ controller/        # Reconciliation logic
β”‚   β”‚   β”œβ”€β”€ s3bucket_controller.go
β”‚   β”‚   └── s3bucket_controller_test.go
β”‚   └── aws/              # AWS SDK wrapper
β”‚       β”œβ”€β”€ s3.go
β”‚       └── types.go
β”œβ”€β”€ config/
β”‚   β”œβ”€β”€ crd/              # Generated CRDs
β”‚   β”œβ”€β”€ rbac/             # RBAC manifests
β”‚   β”œβ”€β”€ manager/          # Controller deployment
β”‚   └── examples/         # Usage examples
β”œβ”€β”€ helm/orbital/         # Helm chart
β”œβ”€β”€ cmd/main.go           # Entry point
β”œβ”€β”€ Makefile              # Build targets
└── README.md
Development Workflow
# 1. Make changes to API
vim api/v1alpha1/s3bucket_types.go

# 2. Regenerate manifests and code
make manifests generate

# 3. Run tests
make test

# 4. Test locally
make run

# 5. Build Docker image
make docker-build IMG=myregistry/orbital:dev

# 6. Deploy to test cluster
make deploy IMG=myregistry/orbital:dev
Running Tests
# Unit tests
make test

# Integration tests with envtest
make test-integration

# Coverage report
make test-coverage
Building from Source
# Build binary
make build

# Build and push Docker image
make docker-build docker-push IMG=ghcr.io/raihankhan/orbital:v0.1.0
Kubebuilder Scaffolding Commands

This project was scaffolded using Kubebuilder. Here are the exact commands used to create the project structure:

# 1. Initialize the project
kubebuilder init \
  --domain orbital.dev \
  --repo github.com/raihankhan/orbital \
  --owner "Orbital Team"

# 2. Create the S3Bucket API and controller
kubebuilder create api \
  --group infra \
  --version v1alpha1 \
  --kind S3Bucket \
  --resource \
  --controller \
  --make

# 3. Generate manifests and code (after modifying types)
make manifests generate

# 4. Install CRDs into the cluster
make install

# 5. Run the controller locally for testing
make run

# 6. Build and deploy to cluster
make docker-build docker-push IMG=<your-registry>/orbital:tag
make deploy IMG=<your-registry>/orbital:tag

Key Files Modified After Scaffolding:

  • api/v1alpha1/s3bucket_types.go - Added CRD fields (bucketName, region, versioning, lifecycle, etc.)
  • internal/controller/s3bucket_controller.go - Implemented reconciliation logic
  • internal/aws/ - Created AWS SDK wrapper for S3 operations
  • config/rbac/ - Added RBAC permissions for Secrets access
  • helm/orbital/ - Created Helm chart for deployment

Kubebuilder Markers Used:

// Validation markers
// +kubebuilder:validation:MinLength=3
// +kubebuilder:validation:MaxLength=63
// +kubebuilder:validation:Pattern=`^[a-z0-9][a-z0-9.-]*[a-z0-9]$`
// +kubebuilder:validation:Enum=us-east-1;us-west-2;ap-south-1;eu-central-1
// +kubebuilder:validation:Minimum=1
// +kubebuilder:validation:Maximum=3650

// Default values
// +kubebuilder:default=Delete

// Resource configuration
// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
// +kubebuilder:resource:scope=Cluster

// RBAC markers
// +kubebuilder:rbac:groups=infra.orbital.dev,resources=s3buckets,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups="",resources=secrets,verbs=get;list;watch

πŸ”„ Reconciliation Process

The Orbital controller follows a standard Kubernetes reconciliation pattern:

1. Fetch Phase
  • Retrieve the S3Bucket CR from the API server
  • Return early if not found (deleted)
2. Deletion Handling
  • Check if CR has deletionTimestamp set
  • If deletionPolicy: Delete, delete the S3 bucket via AWS SDK
  • If deletionPolicy: Retain, skip AWS deletion
  • Remove finalizer to allow CR deletion
3. Finalizer Management
  • Add infra.orbital.dev/finalizer if not present
  • Ensures cleanup logic runs before CR deletion
4. AWS Authentication
  • Fetch Secret referenced in awsSecretRef
  • Extract AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY
  • Initialize AWS S3 client with credentials
5. Bucket Reconciliation
  • Check if bucket exists in AWS (HeadBucket)
  • Create bucket if missing (CreateBucket)
  • Configure versioning (PutBucketVersioning)
  • Idempotent operations ensure safe retries
6. Lifecycle Management
  • Track creationTime in status on first reconcile
  • Calculate scheduledDeletionTime if lifecycle.deleteAfterDays is set
  • Check if current time >= scheduled deletion time
  • Delete bucket and CR if lifecycle policy expired
  • Use RequeueAfter to check again before deletion time
7. Status Update
  • Set phase: Pending, Ready, Error, or Deleted
  • Update observedGeneration to track spec changes
  • Set conditions with type Ready
  • Record timestamps for creation and scheduled deletion
Error Handling
  • All AWS errors are logged and reflected in status
  • Transient errors trigger requeue with exponential backoff
  • Permanent errors (e.g., invalid credentials) set status to Error
  • Controller-runtime handles rate limiting automatically

πŸ› Troubleshooting

Bucket Not Created

Symptoms: CR shows phase: Error or phase: Pending

# Check controller logs
kubectl logs -n orbital-system deployment/orbital-controller-manager

# Check CR status
kubectl describe s3bucket <bucket-name>

# Common causes:
# 1. Invalid AWS credentials
kubectl get secret orbital-aws-creds -o yaml

# 2. Bucket name already exists globally
# 3. Insufficient IAM permissions
# 4. Invalid region
Lifecycle Deletion Not Working

Symptoms: Bucket not deleted after deleteAfterDays

# Check status timestamps
kubectl get s3bucket <bucket-name> -o jsonpath='{.status}'

# Verify scheduledDeletionTime is set
kubectl get s3bucket <bucket-name> -o jsonpath='{.status.scheduledDeletionTime}'

# Check controller is running
kubectl get pods -n orbital-system
Permission Denied Errors

Required IAM Permissions:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:CreateBucket",
        "s3:DeleteBucket",
        "s3:HeadBucket",
        "s3:GetBucketLocation",
        "s3:GetBucketVersioning",
        "s3:PutBucketVersioning"
      ],
      "Resource": "*"
    }
  ]
}
Controller Crashlooping
# Check logs
kubectl logs -n orbital-system deployment/orbital-controller-manager

# Common issues:
# 1. CRDs not installed
kubectl get crd s3buckets.infra.orbital.dev

# 2. RBAC permissions missing
kubectl get clusterrole orbital-manager-role

# 3. Invalid image
kubectl describe pod -n orbital-system <pod-name>

πŸ“š References

🀝 Contributing

Contributions are welcome! Please see CONTRIBUTING.md for guidelines.

Development Setup
  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Make your changes
  4. Run tests (make test)
  5. Commit your changes (git commit -m 'Add amazing feature')
  6. Push to the branch (git push origin feature/amazing-feature)
  7. Open a Pull Request

πŸ“„ License

This project is licensed under the GNU GENERAL PUBLIC LICENSE Version 3.0 - see the LICENSE file for details.

πŸ™ Acknowledgments


Directories ΒΆ

Path Synopsis
api
v1alpha1
Package v1alpha1 contains API Schema definitions for the infra v1alpha1 API group.
Package v1alpha1 contains API Schema definitions for the infra v1alpha1 API group.
internal
aws
test

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL