{"id":19361580,"url":"https://github.com/mxk/oktapus","last_synced_at":"2025-11-18T09:03:07.772Z","repository":{"id":57587866,"uuid":"167592174","full_name":"mxk/oktapus","owner":"mxk","description":"Tool for bulk management of AWS accounts","archived":false,"fork":false,"pushed_at":"2019-02-12T14:03:06.000Z","size":516,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-13T03:49:40.537Z","etag":null,"topics":["aws","aws-organizations","devops","go","golang","okta"],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mxk.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-01-25T18:14:52.000Z","updated_at":"2020-11-13T08:49:09.000Z","dependencies_parsed_at":"2022-09-26T19:42:33.753Z","dependency_job_id":null,"html_url":"https://github.com/mxk/oktapus","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/mxk/oktapus","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mxk%2Foktapus","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mxk%2Foktapus/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mxk%2Foktapus/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mxk%2Foktapus/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mxk","download_url":"https://codeload.github.com/mxk/oktapus/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mxk%2Foktapus/sbom","scorecard":{"id":670217,"data":{"date":"2025-08-11","repo":{"name":"github.com/mxk/oktapus","commit":"77be0571705465216000b0dcf3faa2ab39112fff"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":1.5,"checks":[{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: BSD 3-Clause \"New\" or \"Revised\" License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":0,"reason":"Project has not signed or included provenance with any releases.","details":["Warn: release artifact v0.1.0 not signed: https://api.github.com/repos/mxk/oktapus/releases/15188437","Warn: release artifact v0.1.0 does not have provenance: https://api.github.com/repos/mxk/oktapus/releases/15188437"],"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":0,"reason":"27 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GO-2022-0209 / GHSA-r5c5-pr8j-pfp7","Warn: Project is vulnerable to: GO-2023-1992 / GHSA-x3jr-pf6g-c48f","Warn: Project is vulnerable to: GO-2022-0229 / GHSA-cjjc-xp8v-855w","Warn: Project is vulnerable to: GO-2020-0012 / GHSA-ffhg-7mh4-33c4","Warn: Project is vulnerable to: GO-2021-0227 / GHSA-3vm4-22fp-5rfm","Warn: Project is vulnerable to: GO-2022-0968 / GHSA-gwc9-m7rh-j2ww","Warn: Project is vulnerable to: GO-2021-0356 / GHSA-8c26-wmh5-6g9v","Warn: Project is vulnerable to: GO-2024-2961","Warn: Project is vulnerable to: GO-2023-2402 / GHSA-45x7-px36-x8w8","Warn: Project is vulnerable to: GO-2024-3321 / GHSA-v778-237x-gjrc","Warn: Project is vulnerable to: GO-2025-3487 / GHSA-hcg3-q754-cr77","Warn: Project is vulnerable to: GO-2022-0197 / GHSA-4r78-hx75-jjj2 / GHSA-mv93-wvcp-7m7r","Warn: Project is vulnerable to: GO-2020-0014 / GHSA-vfw5-hrgq-h5wf","Warn: Project is vulnerable to: GO-2022-0536 / GHSA-39qc-96h7-956f / GHSA-hgr8-6h9x-f7q9","Warn: Project is vulnerable to: GO-2022-0236 / GHSA-h86h-8ppg-mxmh","Warn: Project is vulnerable to: GO-2021-0238 / GHSA-83g2-8m93-v3w7","Warn: Project is vulnerable to: GO-2022-0288","Warn: Project is vulnerable to: GO-2022-0969 / GHSA-69cg-p879-7622","Warn: Project is vulnerable to: GO-2022-1144 / GHSA-xrjj-mj9h-534m","Warn: Project is vulnerable to: GO-2023-1571 / GHSA-vvpx-j8f3-3w6h","Warn: Project is vulnerable to: GO-2023-1988 / GHSA-2wrh-6pvc-2jm9","Warn: Project is vulnerable to: GO-2023-2102 / GHSA-4374-p667-p6c8","Warn: Project is vulnerable to: GHSA-qppj-fm5r-hxr3","Warn: Project is vulnerable to: GO-2024-2687 / GHSA-4v7x-pqxf-cx7m","Warn: Project is vulnerable to: GO-2024-3333","Warn: Project is vulnerable to: GO-2025-3503 / GHSA-qxp5-gwg8-xv66","Warn: Project is vulnerable to: GO-2025-3595 / GHSA-vvgc-356p-c3xw"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-21T19:43:46.468Z","repository_id":57587866,"created_at":"2025-08-21T19:43:46.469Z","updated_at":"2025-08-21T19:43:46.469Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":285035891,"owners_count":27103933,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-11-18T02:00:05.759Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aws","aws-organizations","devops","go","golang","okta"],"created_at":"2024-11-10T07:23:59.320Z","updated_at":"2025-11-18T09:03:07.766Z","avatar_url":"https://github.com/mxk.png","language":"Go","readme":"Oktapus\n=======\n\nOktapus is a command-line tool that manages and provides access to multiple AWS\naccounts. One account is used as the gateway. The client authenticates to the\ngateway via IAM user credentials or STS role-based access (e.g. SAML assertion\nprovided by Okta). After authentication, AWS policy associated with the gateway\nuser/role determines which other accounts the client is allowed to access.\n\nEach account may contain a special IAM role called `OktapusAccountControl`,\nwhich is used to store account metadata consisting of the Owner, Description,\nand Tags. This metadata is represented as a JSON object, encoded in base 64, and\nstored in the role description.\n\nIf the gateway account is an AWS Organizations master, and the policy allows the\nclient to call `organizations:CreateAccount` API (and a few related APIs), then\nthe client is also able to create new accounts in the organization. Accounts\ncannot be deleted programmatically (see [Limitations](#limitations)).\n\nSetup\n-----\n\nOkta-based authentication is not covered by these instructions. Use one AWS\naccount as a gateway by following these steps:\n\n1. Use your email address as the name of a new IAM user in your AWS account.\n   Only programmatic access is required.\n2. Run `aws configure [--profile \u003cname\u003e]` to add the user credentials to your\n   aws cli config file. If you use a separate profile, set `OKTAPUS_AWS_PROFILE`\n   environment variable to the profile name.\n3. Send your user ARN to someone who already has access to other accounts.\n   * The following command is used to give account access:\n     ```\n     oktapus authz \u003caccount-spec\u003e \u003cprincipal\u003e ...\n     ```\n   * For example, this command creates a new role called `newuser@example.com`\n     in all accounts with the `test` tag. The role can be assumed by the user\n     `newuser@example.com` from account 123456789012:\n     ```\n     oktapus authz test arn:aws:iam::123456789012:user/newuser@example.com\n     ```\n4. Once your new user is authorized, run `oktapus ls` to confirm access. If you\n   ran any command before, the access errors may still be cached by the daemon.\n   Run `oktapus kill-daemon` to wipe that cache.\n5. Read `oktapus help account-spec` to understand how accounts are specified on\n   the command-line. This argument is expected by most sub-commands.\n\nBasic use\n---------\n\nThese are simple examples of the most common oktapus operations. Run `oktapus`\nto see a list of all available commands. Run `oktapus help \u003ccommand\u003e` to see\ndetailed command help information.\n\n```sh\n# List free accounts\noktapus ls '!owner'\n\n# Open AWS console for an account ID\noktapus cons 123456789012\n\n# Allocate 2 accounts\noktapus alloc 2\n\n# Allow another user to access your accounts\noktapus authz owner=me someone@example.com\n\n# Get long-term credentials for a temporary IAM user\noktapus creds -tmp -user mytmpuser owner=me\n\n# Free accounts allocated to you\noktapus free\n```\n\nDesign\n------\n\n### Authentication\n\nIn the absence of any other configuration, oktapus uses the standard AWS CLI\nconfig files and environment variables to authenticate to the gateway account.\n\nTo use Okta authentication, set `OKTA_ORG` environment variable to your Okta\ndomain name (e.g. `\u003corgname\u003e.okta.com`).\n[Additional variables](https://github.com/oktadeveloper/okta-aws-cli-assume-role#configuring-the-application)\nmay be used to specify your username, the AWS app URL within Okta, and the AWS\nrole to assume (if the SAML assertion contains more than one). `OKTA_PASSWORD`\nis not supported by oktapus.\n\nFor the initial Okta authentication, the client prompts for the username (if not\nset in `OKTA_USERNAME`), password, and MFA, if required. These credentials are\nexchanged for a session cookie, which is stored in the oktapus cache file\n(`~/.cache/.oktapus`). To get AWS credentials, oktapus requests a SAML assertion\nfrom Okta, which is a signed XML document that tells AWS who the subject is and\nwhich role(s) they are allowed to assume via `sts:AssumeRoleWithSAML` API call.\nOktapus exchanges the SAML assertion for temporary security credentials in the\ngateway account.\n\n### Authorization\n\nOnce in the gateway account, the policy associated with the authenticated IAM\nuser or role determines which other accounts the client is allowed to access.\nThere are multiple ways to implement this control. One of them is to use policy\nvariables that allow the client to assume only specially named roles in other\naccounts. The minimal policy to implement this is below:\n\n```\n{\n    \"Version\": \"2012-10-17\",\n    \"Statement\": [\n        {\n            \"Sid\": \"id0\",\n            \"Effect\": \"Allow\",\n            \"Action\": \"sts:AssumeRole\",\n            \"Resource\": [\"arn:aws:iam::*:role/${aws:username}\"]\n        },\n        {\n            \"Sid\": \"id1\",\n            \"Effect\": \"Allow\",\n            \"Action\": \"sts:AssumeRole\",\n            \"Resource\": [\"arn:aws:iam::*:role/${saml:sub}\"]\n        }\n    ]\n}\n```\n\nBoth statements in this policy do the same thing, but the first one only applies\nto IAM users (those not using Okta authentication), while the second one only\napplies to SAML-assumed IAM roles. This policy allows the client to assume a\nrole in any other account, but only if that account contains a role that matches\nthe client's user name. In other words, if the client is authenticated into the\ngateway account as an IAM user�`someone@example.com`, only accounts that have a\nrole named `someone@example.com` will be accessible to that client. The policy\nassociated with that role determines what the client is allowed to do in the\nother account.\n\nFor Okta authentication, `${saml:sub}`, which is the subject ID from the SAML\nassertion, determines the role name in other accounts. By default, Okta sets the\nsubject ID to the user's email address, but this is configurable in Okta's Admin\nsettings.\n\nBecause the client has no control over the IAM user name or Okta's signed SAML\nassertion, the client is not able to gain access to any accounts where the\nappropriately named role does not already exist. This presents a problem when\ncreating new AWS accounts. By default, each new account is provisioned with a\nrole called `OrganizationAccountAccessRole`. Since this role name does not meet\nthe resource restrictions in the policy above, the client would be immediately\nlocked out of any newly created account. To solve this problem, oktapus\nspecifies an explicit initial role for new accounts that the current user is\nallowed to assume, and then creates `OrganizationAccountAccessRole` separately.\n\n### Account ownership\n\nAccount control metadata stored in the `OktapusAccountControl` IAM role defines\nan owner field that behaves like a per-account mutex. The value of the field has\nno special meaning. All that matters for account allocation is whether the field\nis empty or not.\n\nOktapus uses the following algorithm when asked to allocate N accounts (see\n`oktapus help alloc` for more information):\n\n1. All known accounts are filtered according to the `account-spec` argument.\n2. All free accounts (those with an empty owner) are shuffled to randomize their\n   order.\n3. For each free account:\n   1. Get current account control information.\n   2. Merge local changes to avoid overwriting modifications made by other\n      clients.\n   3. If the owner field is still empty, set it to the current user, and update\n      the role description. If the field was not empty, account is skipped.\n   4. Wait for a verification delay (currently set at 10 seconds).\n   5. Get current account control information and confirm that the owner is\n      still set to the current user. If so, the account is allocated.\n   6. Stop allocation once N accounts have been allocated or there are no free\n      accounts remaining.\n4. If N accounts have been allocated, return their credentials to the user.\n   Otherwise, free any allocated accounts and return an error.\n\nThe situation that this algorithm was designed to avoid is one where two\nseparate clients try to allocate the same account at the same time, and both end\nup thinking that their allocation succeeded. The verification delay allows\nsimultaneous updates from multiple clients to propagate and resolve to one final\nversion. When each client retrieves account metadata for the second time, each\none should only see the \"winning\" version, and only one client will consider\nitself the account owner. Theoretically, it is still possible to end up in a\nsplit ownership situation if the update propagation takes an unusually long\ntime, but the chances of this happening are very low.\n\nThe verification delay was determined by running a stress test where 50\nindependent threads attempted to allocate the same account at the same time. A\ntotal of 1,100 trials were performed. A trial passed if exactly one of the 50\nthreads considered themselves the account owner. The verification delay was\ninitialized to 0 and automatically incremented by 1 second after each failed\ntrial. With a delay of 7 seconds, 870 consecutive trials were executed without\nany failures.\n\n### Temporary IAM users/roles\n\nThe `creds` and `authz` commands are used to get account credentials and create\nnew IAM roles, respectively. By default, `creds` returns a set of temporary\ncredentials for the IAM role that was assumed via the gateway account. The\n`authz` command is normally used to grant other users access to an account by\ncreating an appropriately named role that they are allowed to assume.\n\nBoth commands can also be used to create temporary IAM users and roles, which\nare intended to be used only while the account is allocated. Temporary, in this\ncontext, means that user/role is deleted automatically when the account is\nfreed. A temporary IAM user provides long-term credentials that do not expire\nafter one hour. A temporary IAM role allows cross-account access to accounts\nother than the gateway or the organization master.\n\nTemporary users and roles are identified by having `/oktapus/tmp/` set as their\npath. When an account is freed, all IAM users/roles under this path are deleted.\n\nLimitations\n-----------\n\n* AWS accounts cannot be deleted. An account can be closed, but only by the root\n  user, which requires going through the email password reset procedure, and\n  only via the dashboard (no API for this). Any account (closed or otherwise)\n  can be removed from an organization and become a standalone account, but only\n  after configuring support, billing, and contact info, and agreeing to the EULA\n  (all of which must also be done by root):\n  * https://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/close-account.html\n  * https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_accounts_remove.html\n  * https://docs.aws.amazon.com/general/latest/gr/aws_tasks-that-require-root.html\n  * https://aws.amazon.com/blogs/security/aws-organizations-now-supports-self-service-removal-of-accounts-from-an-organization/\n* There is a limit on the number of accounts that can exist in an AWS\n  organization. Increasing the limit requires contacting support:\n  * https://docs.aws.amazon.com/organizations/latest/userguide/orgs_reference_limits.html\n* The JSON object that contains account control information is limited to 750\n  bytes (1000 bytes in base 64 encoding). This is more than enough to store the\n  account owner, description, and tags.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmxk%2Foktapus","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmxk%2Foktapus","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmxk%2Foktapus/lists"}