Interactive command. Opens your browser to deploy an OIDC CloudFormation stack, then waits for the stack to report back.
Usage
fjall connect establishes an OIDC trust between Fjall and one AWS account. Use it to:
- Register the AWS Organizations management account, the first connect after
fjall create organisation. - Connect a standalone AWS account after
fjall create account. - Add another member account to an existing organisation.
fjall create organisation and fjall create account only scaffold project files. Neither establishes AWS trust, so fjall connect is a separate step in both journeys.
Prerequisites
- Authenticated with
fjall login. - Permission in the target AWS account to create IAM roles and CloudFormation stacks.
- Signed in to the target AWS account in your browser.
What It Does
- Checks for existing connections and reads your organisation config.
- Opens your default browser on an AWS CloudFormation quick-create link.
- The stack creates an IAM OIDC provider and a role that Fjall assumes on demand.
- Polls until the stack completes, printing an elapsed-time line.
- Validates the OIDC trust and records the connection against your organisation.
Checking existing connections, Opening AWS CloudFormation, Waiting for CloudFormation, and Validating OIDC connection.
What This Creates in Your Account
fjall connect deploys one CloudFormation stack, FjallOIDCConnector. Every resource it creates carries the tags fjall:managed=true and fjall:org-id=<your organisation id>.
<orgId> is your Fjall organisation id, so the deploy role’s ARN is arn:aws:iam::<account id>:role/fjall/FjallDeploy<orgId>.
The deploy role holds AdministratorAccess
The deploy role’s attached managed policy isarn:aws:iam::aws:policy/AdministratorAccess. Fjall provisions VPCs, ECS services, RDS and Aurora clusters, S3 buckets, Lambda functions, CloudFront distributions, Route 53 zones, ACM certificates, IAM roles and CloudFormation stacks, and a hand-scoped policy would break every time Fjall adds a resource type.
AdministratorAccess is attached to exactly one role in the stack. What that role can actually do is AdministratorAccess intersected with the permissions boundary, so read the two documents together.
The permissions boundary is on by default
The boundary is a customer-managed policy namedFjallDeployBoundary<orgId>. The template’s FjallPermissionsBoundary parameter controls whether it is applied: it accepts true or false and defaults to true. fjall connect sets it to true explicitly on the quick-create link it opens, so a stale published template cannot drop the cap.
A boundary is an intersection, not a grant, so the document leads with Allow on */* and then denies actions no deploy or destroy performs.
The set of denies is a governance tier. Three tiers exist and they are cumulative: foundation is a subset of compliance, which is a subset of hardened. The quick-create template has no tier parameter, so fjall connect always installs hardened, and hardened is also what the CDK equivalent renders when no tier is set. The tier only ever changes which ceiling the role gets, never whether it has one.
Every deny names an action CloudFormation never performs on your behalf, which is why they are narrower than they look:
cloudtrail:StopLogging and not DeleteTrail, kms:DisableKey and not ScheduleKeyDeletion, config:StopConfigurationRecorder and not DeleteConfigurationRecorder. Destroying a trail, a key or a recorder as part of a stack teardown still works.
The full document is in the reference below. To pick a tier other than hardened, see the governance profile on fjall create organisation.
The boundary policy is an account-global singleton
FjallDeployBoundary<orgId> is one policy per AWS account, shared by every Fjall stack in it, and it is deliberately not owned by any stack. A Custom::FjallDeployBoundary resource adopts the policy by name when it already exists and creates it otherwise, exactly as the OIDC provider resource does.
That shape is what makes connecting a second account, or re-connecting an existing one, safe. A stack-owned managed policy could never be deleted once cdk bootstrap had capped an execution role with it (DeleteConflict), and a retained one would fail the next connect with EntityAlreadyExists.
The writer only ever publishes a document matching one of the three tiers, and it will not weaken a policy that is already in place:
- Deploying the same tier is a no-op — nothing is written.
- Deploying a tighter tier converges the policy in place as a new default version. IAM caps a policy at five versions, so the oldest non-default version is rotated out first.
- Deploying a looser tier fails the stack update rather than lowering the ceiling. Widening is an administrator action, run from a principal outside the boundary.
UPDATE_ROLLBACK_FAILED, always on the stricter side. Recover with the same credentials that ran the deploy:
FjallDeployBoundaryPolicy is the resource’s logical id in the quick-create template; a CDK-rendered connector uses the hashed id of its DeployBoundary construct, which aws cloudformation list-stack-resources shows. Setting the policy’s default version back by hand is not an alternative for the deploy role: iam:SetDefaultPolicyVersion on the boundary is one of the actions the boundary denies to itself, so that path is administrator-only.
The CDK execution role is capped by the same policy
Fjall deploys through CDK, which assumes its own bootstrap execution role,cdk-hnb659fds-cfn-exec-role-<account id>-<region>. That role also holds AdministratorAccess, so capping the deploy role alone would leave the hand-off wider than the role that made it. Every fjall bootstrap therefore looks for FjallDeployBoundary<orgId> in the account and, when it is there, passes it to cdk bootstrap as the execution role’s boundary. That is the second entry in the boundary’s own self-protection scope, role/cdk-*-cfn-exec-role-*.
The two roles are capped on different schedules, because the policy has to exist before a bootstrap can point at it. See two-pass convergence for what that means on a new account and how to check where you are.
Turning the boundary off
There are two opt-outs, one per lane, and both are create-time decisions:
Either one renders no boundary policy and leaves
FjallDeploy<orgId> holding AdministratorAccess with nothing above it. Because the policy is also what caps the CDK execution role, opting out uncaps both roles: nothing then stops a mistaken or compromised deploy leaving the organisation, closing the account, stopping CloudTrail, disabling a KMS key, or minting IAM users with standing credentials.
deployRoleBoundary is not called permissionsBoundary on purpose. CDK’s own permissionsBoundary on StackProps is a different, stack-wide mechanism; this one governs the FjallDeploy role only. Setting both securityTier and deployRoleBoundary: false contradicts itself and fails at synth rather than silently picking one.
What the boundary does not stop
The boundary is a ceiling on accidental and negligent CloudFormation actions, and on the direct self-edits in the table above. It is not a hard cap against a hostile session that already holds the deploy role. That session still hasAdministratorAccess minus the denies, so it could assume an unbounded role that already exists in the account — OrganizationAccountAccessRole exists in every member account — rather than escalating in place.
Treat the boundary as one layer. The others are the OIDC trust policy above it (the deploy role is assumable only by your organisation’s subjects), the one-hour session cap, and, in an organisation, the service control policies the Enforced governance profile installs.
Sessions last one hour
MaxSessionDuration on the deploy role is 3600 seconds. Credentials are minted per operation and are not refreshed while a command runs, which is why fjall aws exec caps --timeout at 1h (default 10m). Split longer work into shorter phases.
Development accounts get four extra resources. When
--environment development is passed, the stack also creates the managed policy FjallDevBoundary and the roles FjallDevDeploy<orgId>, FjallDevProvisioner<orgId> and FjallDevSyncWriter<orgId>. The three roles carry narrow inline policies scoped to dev-tier resources, never AdministratorAccess. No other stage renders them.Removing the boundary policy at end of life
Because no stack owns the policy, no stack deletion removes it.fjall org destroy does, as a reference-counted sweep: for each account, once that account’s stack is gone, it checks whether any role, user or group still lists FjallDeployBoundary<orgId> and deletes the policy only when nothing does. It never un-caps a role to make the delete succeed.
The order matters, and it is why a first destroy pass usually leaves the policy behind:
- Destroy the account’s stacks first. The
FjallDeployrole goes with them, and while it exists it counts as a live reference. - The CDK execution role in every bootstrapped region carries the same policy, and it lives in the
CDKToolkitstack, outside everything Fjall destroys. While any of those survive, the policy is retained by design. - Remove the bootstrap stacks — or un-cap those roles from an administrator principal — and re-run the destroy. The sweep then removes the policy.
Reference: the IAM documents the stack installs
Reference copies of the two policy documents, so you can diff them against the stack in the CloudFormation console before you create it. Both are shown with the template’s parameters named.
Trust policy on
FjallDeploy<orgId>:
FjallMachineSubjectmatches onStringEquals, soorg:${FjallOrgId}:*is an exact literal subject, not a wildcard. Only that sentinel and the account-scopedorg:${FjallOrgId}:acct:${AWS::AccountId}match.FjallUserSubjectsmatches onStringLike, soorg:${FjallOrgId}:user:*does match any user subject in your organisation.- The template branches the trust policy on the account’s tier. Both branches currently render the document above.
FjallDeployBoundary<orgId>:
Interactive Flow
Runfjall connect with no flags in a terminal. It prompts only for what it cannot already determine:
After the prompts, the browser opens automatically. If it does not, the CLI prints
If the browser doesn't open automatically, visit: <url>.
On success the interactive frame shows the completed step list, the next command to run (fjall account deploy), and a docs link. The Account ID, Status, Region and External ID block belongs to the plain-CLI output (--non-interactive, --no-wait, or agent mode).
First connect after
fjall create organisation. When the fjall/organisation scaffold exists locally and no AWS account has connected yet, Fjall skips the region and environment prompts and registers the account as the AWS Organizations management account (tier organisation). Only the name prompt is shown. A standalone fjall/account scaffold does not qualify, so a solo account is never silently rooted.fjall connect short-circuits with AWS account already connected and exits without touching AWS.
Options
The management account’s tier is set by context during organisation setup, never by
--environment.
Agent options
For AI-agent and scripted use,connect and connect status also accept the standard agent flags:
Examples
Interactive
Connect a named staging account
Non-interactive
--environment is required here. Without it the command fails with the valid stage list, unless this is the first connect after fjall create organisation.
Scripted, without blocking on CloudFormation
--no-wait returns as soon as the quick-create URL is issued, so a script can hand the URL to an operator and poll separately.
Re-issue a stack for an existing connection
Typical workflow
Standalone account:Check Connection Status
fjall connect status reads the connection lifecycle, including accounts marked disconnected.
The overview prints one row per connection as
<account id> <status> tier=<tier> stage=<stage> <name>. The single-connection form prints Status, Phase, and, where the server supplies them, Reason, Cure and Account.
Restore a Disconnected Account
fjall reconnect restores OIDC trust for an account the scanner has marked disconnected, for example after the connector stack was torn down. It repairs trust in place, without re-tiering or renaming the account.
fjall reconnect for a disconnected account and --force for a connection that is already active. The two cases are different and the CLI routes them separately.
Troubleshooting
Browser does not open
Copy the URL from the terminal output and open it manually, then sign in to the correct AWS account.Stack deployment fails
Check that the AWS account can create IAM roles and CloudFormation stacks, then rerunfjall connect to re-open the browser flow.
Non-interactive run rejects --environment
--environment accepts workload stages only. Pass one of production, staging, development, platform or compliance. root is not a valid input, because the management account’s tier comes from context.
Connection already exists
fjall connect short-circuits on a matching active connection. To connect a different AWS account, sign in to that account in your browser and rerun. To re-issue the stack for the same account, region and environment, add --force.
Account shows as disconnected
Runfjall connect status to confirm the phase, then fjall reconnect to restore trust. --force is the wrong cure here.
The OIDC connection issues short-lived credentials, so no long-term secrets are stored. Fjall assumes the IAM role on demand through OpenID Connect federation, and never reads or writes
~/.aws/config.Next Steps
Deploy an account
Run
fjall account deploy to provision the account tier after connecting.Deploy an organisation
Create member accounts and provision every tier with
fjall org deploy.fjall create
Scaffold an organisation, an account, or an application.
Understanding Profiles
See how AWS profiles and deployment targets are derived from org config.