Give the role the two things a cloud box needed, and stop asking for them each time - #12
Merged
Merged
Conversation
…them each time Provisioning a fresh EC2 box surfaced three defaults written for a laptop: the login shell lives inside the Homebrew prefix, the home is required to sit on its own filesystem, and the Brewfile assumes brew is installed. A cloud image has none of that, so two of the role's own guards refuse the run and the third would install nothing. Each was answerable, but answering them by hand on every box is how a preset earns its place. `ansible/hosts/lily.yml` is that preset — the shell, the filesystem requirement and the Brewfile turned off, Claude Code turned on, and the authorized keys. It is passed with `-e @hosts/lily.yml` rather than made role defaults: a fork of this public repo that inherited the keys would provision boxes those keys can log into. That placement is also the only one that works, since `-e` replaces the variable wholesale and a key added to defaults is discarded on every run that passes the preset. `ansible/security-group.yml` opens ssh to an address on the group a box already carries. It takes an instance ARN and an address and reads everything else from them: the region and instance id are ARN fields, and the group is read off the instance, so nothing here names a box or a group. Four things it refuses rather than guesses — missing inputs, an ARN that is not an EC2 instance, an address carrying its own prefix, and an instance that returns anything other than exactly one group. `purge_rules` is false and commented, because the default strips every rule the play was not told about, which on a shared group is how it would quietly take ssh away from somebody else. The play runs from the operator's machine rather than the target. A box's own instance profile has no business holding ec2:AuthorizeSecurityGroupIngress, and the ones this was written against do not. Claude-Session: https://claude.ai/code/session_01C9wuTPhHTSS4pvqgTq3A26
…at needs it The role and the security-group play both live here, and neither runs without ansible-playbook. Homebrew's formula is the whole community package rather than ansible-core, so it brings amazon.aws, ansible.posix and community.general with it — which is every collection requirements.yml asks for, and the reason a galaxy install is not also needed. Claude-Session: https://claude.ai/code/session_01C9wuTPhHTSS4pvqgTq3A26
… hand Both were commented out on the reasoning that root is a per-host decision, which is true of the role's defaults and not of this file: a preset for boxes provisioned to be worked on is exactly the place that decision gets made. The docker group is root-equivalent on a rootful daemon, so a preset granting one and withholding the other was not a smaller grant, only a less usable box. Claude-Session: https://claude.ai/code/session_01C9wuTPhHTSS4pvqgTq3A26
Two defects a review of the branch turned up, both of which ran green. The play promised a /32 per address and delivered one only for IPv4. An IPv6 address took the same suffix, and the module normalizes what it is handed to a network address, so 2001:db8::1 arrived as 2001:db8::/32 -- not one host but 2^96 of them. It failed, but on an IPv4 field rejecting an IPv6 value rather than on anything checking, so the same input against a play that spelled the field correctly would have opened the widest rule on the group. The address family is now checked, which also catches input that is not an address at all and used to travel as far as AWS. dev_user_groups went straight into the user module, which fails on a group it cannot find rather than creating it. That made every name in the list something the target had to already have -- and the preset added docker, so a stock cloud image stopped being provisionable at account creation. Groups are now granted where they exist and named where they do not, which is how the brew prefix above is already handled: docker on a box with no daemon is a name, not access. Claude-Session: https://claude.ai/code/session_01C9wuTPhHTSS4pvqgTq3A26
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Provisioning a fresh EC2 box surfaced three defaults written for a laptop: the login shell lives inside the Homebrew prefix, the home is required to sit on its own filesystem, and the Brewfile assumes brew is installed. A cloud image has none of that, so two of the role's own guards refuse the run and the third would install nothing. Each was answerable, but answering them by hand on every box is how a preset earns its place.
ansible/hosts/lily.ymlis that preset — the shell, the filesystem requirement and the Brewfile turned off, Claude Code turned on, and the authorized keys. It is passed with-e @hosts/lily.ymlrather than made role defaults: a fork of this public repo that inherited the keys would provision boxes those keys can log into. That placement is also the only one that works, since-ereplaces the variable wholesale and a key added to defaults is discarded on every run that passes the preset.ansible/security-group.ymlopens ssh to an address on the group a box already carries. It takes an instance ARN and an address and reads everything else from them: the region and instance id are ARN fields, and the group is read off the instance, so nothing here names a box or a group. Four things it refuses rather than guesses — missing inputs, an ARN that is not an EC2 instance, an address carrying its own prefix, and an instance that returns anything other than exactly one group.purge_rulesis false and commented, because the default strips every rule the play was not told about, which on a shared group is how it would quietly take ssh away from somebody else.The play runs from the operator's machine rather than the target. A box's own instance profile has no business holding ec2:AuthorizeSecurityGroupIngress, and the ones this was written against do not.
https://claude.ai/code/session_01C9wuTPhHTSS4pvqgTq3A26