Conjure a private bucket
$ grim infra:aws-s3 --scope=per-env --project=shop --env=production
Uploads that live on the server's disk tie the app to that one server. The day you want a second machine, or a staging copy that cannot damage production files, they have to move to object storage. grim infra:aws-s3 makes the bucket, makes credentials that open that bucket and nothing else, and prints them in the shape Laravel's s3 disk reads.
It prints. It does not write your .env and it does not touch a server. Getting the values where they belong is a second, deliberate step.
Usage
$ grim infra:aws-s3 --dry-run # the plan and an estimate, nothing created
$ grim infra:aws-s3 # the wizard
$ grim infra:aws-s3 --scope=per-env --project=shop --env=staging # no questions about scope
$ grim infra:aws-s3 --scope=standalone --bucket=acme-shared-assets # a bucket outside any projectRun it from anywhere. It needs the aws CLI, terraform and working AWS credentials; grim infra:doctor checks them. For the two project scopes, the wizard offers the projects and environments registered in ~/.grim/servers.json.
Arguments and options
Create a private S3 bucket + scoped IAM user, ready for Laravel filesystems.disks.s3
Usage
grim infra:aws-s3 [--region REGION] [--scope SCOPE] [--project PROJECT] [--env ENV] [--bucket BUCKET] [--no-versioning] [--no-tiering] [--profile PROFILE] [--dry-run] [--force]Options
| Option | Description |
|---|---|
--region=REGION |
AWS region for the bucket (default: eu-central-1) |
--scope=SCOPE |
Scope: per-env | per-project | standalone |
--project=PROJECT |
Project name (for per-env / per-project scopes) |
--env=ENV |
Environment (for per-env scope, defaults to project default) |
--bucket=BUCKET |
Override bucket name (default: auto-suggested from scope) |
--no-versioning |
Disable S3 object versioning |
--no-tiering |
Skip Intelligent-Tiering lifecycle |
--profile=PROFILE |
AWS CLI profile to use |
--dry-run |
Show plan only, do not provision |
--force |
Allow re-using an existing state directory |
Three scopes
| Scope | Bucket name | Use it when |
|---|---|---|
per-env |
grim-<project>-<env>-storage-<account> |
The default. Staging and production get a bucket each, so a staging deploy can never overwrite a production upload. |
per-project |
grim-<project>-storage-<account> |
One bucket for every environment of a project. Fewer buckets, and the risk above is yours. |
standalone |
grim-bucket-<account>-<random>, or your own |
Shared assets, dumps, anything that belongs to no project. The wizard asks for the name. |
--bucket overrides the name in any scope. Bucket names are global across all of AWS, which is why the account number is part of the suggestion.
What it actually does
- Shows the AWS identity and asks whether to create resources in that account. The default answer is no.
- Resolves scope, project, environment, bucket name and region. The region is
eu-central-1unless you pass--region; the wizard does not ask. - Prints the plan with a monthly estimate for a small bucket, from the price snapshot built into grim. With
--dry-runit stops here. - Runs Terraform in
~/.grim/infra/s3-<id>/after a second confirmation. The id is<project>-<env>,<project>orstandalone-<random>. - Records the bucket under
aws_resourcesin~/.grim/servers.jsonass3-<id>: bucket name, IAM user, region, project, environment, scope, account and profile. - Prints the
.envblock.AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY,AWS_DEFAULT_REGION,AWS_BUCKETandAWS_URL. For aper-envbucket it adds the matchinggrim env:setlines for that environment, with the secret left for you to fill in.
What exists in AWS afterwards
The bucket, with all four public access blocks on, AES256 encryption at rest, versioning, a CORS rule that lets any origin GET, PUT, POST and HEAD, and Intelligent-Tiering that moves objects to the archive tier after 90 days and the deep archive tier after 180. --no-versioning and --no-tiering switch those two off. The rest has no flag.
An IAM user named grim-<id>-s3 under the path /grim-cli/, with one inline policy and one access key. The policy allows listing that bucket and reading, writing and deleting objects and object versions in it, including multipart uploads and object ACLs. It names no other resource, so a leaked key costs you one bucket.
The secret key is printed once and grim never prints it again. It is not gone, though: Terraform keeps it in plain text in ~/.grim/infra/s3-<id>/terraform.tfstate. Treat that directory like a password store, and copy the block into the server's .env before you close the terminal.
Pitfalls
The bucket name is taken by someone else
Provisioning failed: followed by a hint about a bucket name conflict means another AWS customer owns that name. The state directory stays, so a plain second run stops with S3 state already exists. Run again with a different --bucket and --force, which reuses that directory.
The wizard finds no projects
No grim projects registered. Use --scope=standalone or run grim server:add-project first. appears when servers.json holds no project. The project scopes only pick from registered projects. Pass --project and --env yourself, or register the project first.
The app still writes to local disk
The credentials alone change nothing. Laravel uses the bucket only when the disk it writes to is s3, which in a stock app means FILESYSTEM_DISK=s3 next to the five lines above.
After it finishes
Put the values on the server and recreate the containers so the app reads them. From the project directory:
$ grim env:pull production # fetch the server's .env as .env.production
$ grim env:push production --restart # after pasting the block into itgrim env:pull describes that round trip. For a single value grim env:set is shorter. The bucket now shows in grim infra:list as s3-shop-production, and that id is what grim infra:destroy takes.
Related spells
grim infra:aws-cloudtrail
Keep an account audit trail
Turn on a CloudTrail trail that records API activity in every region of the account into a locked-down S3 bucket, at a level of detail you pick from four presets.
grim infra:aws-budget
Set a spending alarm
Create a monthly AWS budget that mails you at 50, 80 and 100 percent of a limit, and when AWS forecasts the month will end above it.
grim infra:list
Survey what runs on AWS
List every server and AWS resource grim has created, with a monthly cost estimate for each and the ids that infra:destroy takes.
grim infra:destroy
Unmake what grim made
Remove a server or AWS resource that grim created, after checking the account and making you type its name, and stop it from being billed.
grim env:set
Change one server variable
Set a single KEY=VALUE in the .env of a deployed environment and recreate the containers so the app runs on it at once.
grim env:push
Send a .env back
Upload your edited .env.<environment> over the .env of a deployed environment, and optionally recreate the containers that read it.