├── .editorconfig ├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── config.yml │ └── feature_request.md ├── PULL_REQUEST_TEMPLATE.md ├── dependabot.yml └── workflows │ ├── codeql-analysis.yml │ ├── docs-verify.yml │ ├── golangci-lint.yml │ ├── labeler.yml │ ├── main.yml │ ├── release-docs.yml │ ├── release.yml │ └── titlecheck.yml ├── .gitignore ├── .gitmodules ├── .golangci.yml ├── .goreleaser.yml ├── .krew.yaml ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Dockerfile ├── Dockerfile.alpine ├── Dockerfile.deps ├── LICENSE ├── Makefile ├── README.md ├── SECURITY.md ├── api └── v1alpha1 │ ├── configuration_types.go │ ├── history_types.go │ ├── history_types_internal_test.go │ ├── register.go │ └── zz_generated.deepcopy.go ├── cmd └── kconnect │ └── main.go ├── docs ├── .gitkeep ├── README.md ├── artefacts │ ├── hl.png │ ├── sequence.plantuml │ └── sequence.png ├── book │ ├── .gitignore │ ├── book.toml │ ├── src │ │ ├── SUMMARY.md │ │ ├── commands │ │ │ ├── alias.md │ │ │ ├── alias_add.md │ │ │ ├── alias_ls.md │ │ │ ├── alias_remove.md │ │ │ ├── config.md │ │ │ ├── history.md │ │ │ ├── history_export.md │ │ │ ├── history_import.md │ │ │ ├── history_rm.md │ │ │ ├── index.md │ │ │ ├── logout.md │ │ │ ├── ls.md │ │ │ ├── to.md │ │ │ ├── use.md │ │ │ ├── use_aks.md │ │ │ ├── use_eks.md │ │ │ ├── use_oidc.md │ │ │ ├── use_rancher.md │ │ │ └── version.md │ │ ├── contributing.md │ │ ├── getting-started.md │ │ ├── images │ │ │ └── kconnectfrontpage.gif │ │ ├── installation.md │ │ ├── introduction.md │ │ └── release.md │ └── theme │ │ ├── css │ │ └── general.css │ │ ├── favicon.png │ │ └── head.hbs └── proposals │ ├── 20200607-initial-design.md │ ├── 20200630-cli-ux.md │ ├── 20200827-history.md │ └── YYYYMMDD-template.md ├── examples └── config.yaml ├── go.mod ├── go.sum ├── hack ├── boilerplate.generatego.txt └── tools │ ├── go.mod │ ├── go.sum │ └── tools.go ├── internal ├── commands │ ├── alias │ │ ├── add.go │ │ ├── alias.go │ │ ├── ls.go │ │ └── remove.go │ ├── config │ │ └── config.go │ ├── history │ │ ├── export.go │ │ ├── history.go │ │ ├── import.go │ │ └── rm.go │ ├── logout │ │ └── logout.go │ ├── ls │ │ └── ls.go │ ├── root.go │ ├── to │ │ └── to.go │ ├── use │ │ └── use.go │ └── version │ │ └── version.go ├── helpers │ └── common.go └── version │ ├── checker.go │ └── version.go ├── pkg ├── app │ ├── alias.go │ ├── app.go │ ├── config.go │ ├── configure.go │ ├── errors.go │ ├── history.go │ ├── list.go │ ├── logout.go │ ├── to.go │ └── use.go ├── aws │ ├── awsconfig │ │ └── awsconfig.go │ ├── clients.go │ ├── config.go │ ├── errors.go │ ├── identifer.go │ ├── identity.go │ ├── map.go │ ├── resolve.go │ └── store.go ├── azure │ ├── client │ │ └── client.go │ ├── id │ │ ├── cluster.go │ │ ├── cluster_test.go │ │ ├── resource.go │ │ └── resource_test.go │ ├── identity │ │ ├── authorizer.go │ │ ├── client.go │ │ ├── endpoints.go │ │ ├── errors.go │ │ ├── identity.go │ │ └── types.go │ └── wstrust │ │ ├── mex_document_definitions.go │ │ ├── saml_assertion_definitions.go │ │ ├── saml_token_info.go │ │ ├── wstrust_endpoint.go │ │ ├── wstrust_mex_document.go │ │ └── wstrust_response.go ├── config │ ├── apply.go │ ├── configset.go │ ├── configuration.go │ ├── errors.go │ └── unmarshall.go ├── defaults │ ├── defaults.go │ └── http.go ├── errors │ └── validation.go ├── flags │ ├── flags.go │ ├── flags_test.go │ ├── unmarshal.go │ └── unmarshal_test.go ├── history │ ├── filter.go │ ├── filter_test.go │ ├── history.go │ ├── loader │ │ ├── loader.go │ │ └── mock_loader │ │ │ ├── doc.go │ │ │ └── loader_mock.go │ ├── store.go │ ├── store_test.go │ └── time │ │ └── time.go ├── http │ ├── http_client.go │ └── types.go ├── k8s │ └── kubeconfig │ │ └── kubeconfig.go ├── logging │ └── logging.go ├── matchers │ └── history.go ├── oidc │ ├── config.go │ └── identity.go ├── plugins │ ├── discovery │ │ ├── aws │ │ │ ├── config.go │ │ │ ├── discover.go │ │ │ ├── errors.go │ │ │ ├── get.go │ │ │ ├── provider.go │ │ │ └── resolver.go │ │ ├── azure │ │ │ ├── config.go │ │ │ ├── defaults.go │ │ │ ├── discover.go │ │ │ ├── errors.go │ │ │ ├── get.go │ │ │ ├── provider.go │ │ │ ├── resolver.go │ │ │ └── types.go │ │ ├── oidc │ │ │ ├── config.go │ │ │ ├── discover.go │ │ │ ├── get.go │ │ │ ├── provider.go │ │ │ └── resolver.go │ │ ├── plugins.go │ │ └── rancher │ │ │ ├── config.go │ │ │ ├── discover.go │ │ │ ├── errors.go │ │ │ ├── get.go │ │ │ ├── provider.go │ │ │ ├── resolver.go │ │ │ └── types.go │ ├── identity │ │ ├── aws │ │ │ └── iam │ │ │ │ └── provider.go │ │ ├── azure │ │ │ ├── aad │ │ │ │ ├── aad.go │ │ │ │ └── resolver.go │ │ │ └── env │ │ │ │ └── provider.go │ │ ├── oidc │ │ │ └── provider.go │ │ ├── plugins.go │ │ ├── rancher │ │ │ └── activedirectory │ │ │ │ ├── activedirectory.go │ │ │ │ ├── resolver.go │ │ │ │ └── types.go │ │ ├── saml │ │ │ ├── saml.go │ │ │ └── sp │ │ │ │ ├── aws │ │ │ │ ├── provider.go │ │ │ │ └── resolver.go │ │ │ │ └── types.go │ │ └── static │ │ │ └── token │ │ │ └── token.go │ └── plugins.go ├── printer │ └── printer.go ├── prompt │ └── prompt.go ├── provider │ ├── common │ │ └── common.go │ ├── config │ │ └── config.go │ ├── discovery │ │ └── discovery.go │ ├── errors.go │ ├── identity │ │ ├── identity.go │ │ └── token.go │ ├── registry │ │ └── registry.go │ ├── selection.go │ └── types.go ├── rancher │ ├── config.go │ ├── endpoints.go │ ├── errors.go │ └── resolve.go └── utils │ ├── command.go │ ├── filter.go │ ├── prerequisites.go │ └── utils_test.go ├── scripts └── install-kconnect.sh └── tools └── cmddocsgen └── cmddocsgen.go /.editorconfig: -------------------------------------------------------------------------------- 1 | ; http://editorconfig.org/ 2 | 3 | root = true 4 | ; 5 | [*] 6 | charset = utf-8 7 | 8 | end_of_line = lf 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | 12 | indent_size = 4 13 | indent_style = space 14 | 15 | [*.go] 16 | indent_style = tab 17 | 18 | [{*.html, *.css, *.scss}] 19 | indent_size = 2 20 | 21 | [{*.yaml, *.yml, *.json}] 22 | indent_size = 2 23 | 24 | [Makefile] 25 | indent_style = tab 26 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Global owners 2 | * @rajarajanpsj @Gearheads @kishoregv @niroowns @aido123 @precompiler @awatterson22 @felixdeleon @gseshagirirao -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Tell us about a problem you are experiencing 4 | title: '' 5 | labels: kind/bug 6 | assignees: '' 7 | --- 8 | 9 | **What happened:** 10 | [A clear and concise description of what the bug is.] 11 | 12 | 13 | **What did you expect to happen:** 14 | 15 | 16 | **How to reproduce it:** 17 | 18 | 19 | **Anything else you would like to add:** 20 | [Miscellaneous information that will assist in solving the issue.] 21 | 22 | 23 | **Environment:** 24 | 25 | - kconnect version (use `kconnect version`): 26 | - Kubernetes version (use `kubectl version`): 27 | - OS (e.g. from `/etc/os-release`): 28 | - Target environment (e.g. EKS, AKS, Rancher): 29 | - Authentication Used (e.g. SAML, IAM, Azure AD): -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature enhancement request 3 | about: Suggest an idea for kconnect 4 | title: '' 5 | labels: kind/feature 6 | assigness: '' 7 | --- 8 | 9 | **Describe the solution you'd like:** 10 | [A clear and concise description of what you want to happen.] 11 | 12 | **Why do you want this feature:** 13 | 14 | **Anything else you would like to add:** 15 | [Miscellaneous information that will assist in solving the issue.] 16 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | **What this PR does / why we need it**: 2 | 3 | **Which issue(s) this PR fixes** *(optional, in `fixes #(, fixes #, ...)` format, will close the issue(s) when PR gets merged)*: 4 | Fixes # -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "gomod" 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" 7 | - package-ecosystem: "gomod" 8 | directory: "/hack/tools" 9 | schedule: 10 | interval: "weekly" 11 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | name: "CodeQL" 7 | 8 | on: 9 | push: 10 | branches: [main] 11 | pull_request: 12 | # The branches below must be a subset of the branches above 13 | branches: [main] 14 | schedule: 15 | - cron: '0 20 * * 5' 16 | 17 | jobs: 18 | analyze: 19 | name: Analyze 20 | runs-on: ubuntu-latest 21 | 22 | strategy: 23 | fail-fast: false 24 | matrix: 25 | # Override automatic language detection by changing the below list 26 | # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python'] 27 | language: ['go'] 28 | # Learn more... 29 | # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection 30 | 31 | steps: 32 | - name: Checkout repository 33 | uses: actions/checkout@v4 34 | with: 35 | # We must fetch at least the immediate parents so that if this is 36 | # a pull request then we can checkout the head. 37 | fetch-depth: 2 38 | submodules: true 39 | 40 | # If this run was triggered by a pull request event, then checkout 41 | # the head of the pull request instead of the merge commit. 42 | - run: git checkout HEAD^2 43 | if: ${{ github.event_name == 'pull_request' }} 44 | 45 | # Initializes the CodeQL tools for scanning. 46 | - name: Initialize CodeQL 47 | uses: github/codeql-action/init@v3 48 | with: 49 | languages: ${{ matrix.language }} 50 | # If you wish to specify custom queries, you can do so here or in a config file. 51 | # By default, queries listed here will override any specified in a config file. 52 | # Prefix the list here with "+" to use these queries and those in the config file. 53 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 54 | 55 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 56 | # If this step fails, then you should remove it and run the build manually (see below) 57 | #- name: Autobuild 58 | # uses: github/codeql-action/autobuild@v1 59 | 60 | # ℹ️ Command-line programs to run using the OS shell. 61 | # 📚 https://git.io/JvXDl 62 | 63 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 64 | # and modify them (or add more) to build your code if your project 65 | # uses a compiled language 66 | 67 | - run: | 68 | make build 69 | 70 | - name: Perform CodeQL Analysis 71 | uses: github/codeql-action/analyze@v3 72 | -------------------------------------------------------------------------------- /.github/workflows/docs-verify.yml: -------------------------------------------------------------------------------- 1 | name: docs-verify 2 | 3 | on: [pull_request] 4 | 5 | jobs: 6 | verify-docs: 7 | runs-on: ubuntu-latest 8 | name: Verify Docs 9 | steps: 10 | - name: Checkout repository 11 | uses: actions/checkout@v4 12 | with: 13 | fetch-depth: 2 14 | submodules: true 15 | - name: Verify Docs 16 | run: make docs-verify 17 | - name: Build Docs 18 | run: make docs-build 19 | -------------------------------------------------------------------------------- /.github/workflows/golangci-lint.yml: -------------------------------------------------------------------------------- 1 | name: golangci-lint 2 | on: 3 | push: 4 | tags: 5 | - "*" 6 | branches: 7 | - main 8 | pull_request: 9 | permissions: 10 | contents: read 11 | # Optional: allow read access to pull request. Use with `only-new-issues` option. 12 | # pull-requests: read 13 | jobs: 14 | golangci: 15 | name: lint 16 | runs-on: ubuntu-latest 17 | steps: 18 | - uses: actions/setup-go@v5 19 | with: 20 | go-version: '1.22' 21 | cache: false 22 | - uses: actions/checkout@v4 23 | - name: golangci-lint 24 | uses: golangci/golangci-lint-action@v3 25 | with: 26 | # Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version 27 | version: latest 28 | 29 | # Optional: working directory, useful for monorepos 30 | # working-directory: somedir 31 | 32 | # Optional: golangci-lint command line arguments. 33 | # args: --issues-exit-code=0 34 | 35 | # Optional: show only new issues if it's a pull request. The default value is `false`. 36 | # only-new-issues: true 37 | 38 | # Optional: if set to true then the all caching functionality will be complete disabled, 39 | # takes precedence over all other caching options. 40 | # skip-cache: true 41 | 42 | # Optional: if set to true then the action don't cache or restore ~/go/pkg. 43 | # skip-pkg-cache: true 44 | 45 | # Optional: if set to true then the action don't cache or restore ~/.cache/go-build. 46 | # skip-build-cache: true 47 | -------------------------------------------------------------------------------- /.github/workflows/labeler.yml: -------------------------------------------------------------------------------- 1 | name: labeler 2 | 3 | on: [pull_request] 4 | 5 | jobs: 6 | labeler: 7 | runs-on: ubuntu-latest 8 | name: Label the PR size 9 | steps: 10 | - uses: codelytv/pr-size-labeler@v1 11 | with: 12 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 13 | xs_max_size: '50' 14 | s_max_size: '200' 15 | m_max_size: '1500' 16 | l_max_size: '5000' 17 | fail_if_xl: 'false' 18 | message_if_xl: 'This PR is so big! Please, split it 😊' 19 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | # Run on PR 4 | on: 5 | pull_request: 6 | types: 7 | - opened 8 | - edited 9 | - synchronize 10 | - reopened 11 | 12 | jobs: 13 | build: 14 | # The type of runner that the job will run on 15 | runs-on: ubuntu-latest 16 | 17 | # Steps represent a sequence of tasks that will be executed as part of the job 18 | steps: 19 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it 20 | - uses: actions/checkout@v4 21 | with: 22 | submodules: true 23 | 24 | # Build 25 | - name: Build 26 | run: make build 27 | test: 28 | needs: build 29 | # The type of runner that the job will run on 30 | runs-on: ubuntu-latest 31 | 32 | # Steps represent a sequence of tasks that will be executed as part of the job 33 | steps: 34 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it 35 | - uses: actions/checkout@v4 36 | with: 37 | submodules: true 38 | 39 | # Run tests 40 | - name: Tests 41 | run: make test 42 | # lint: 43 | # # The type of runner that the job will run on 44 | # runs-on: ubuntu-latest 45 | 46 | # # Steps represent a sequence of tasks that will be executed as part of the job 47 | # steps: 48 | # # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it 49 | # - uses: actions/checkout@v3 50 | # with: 51 | # submodules: true 52 | # - name: Set up Go 53 | # uses: actions/setup-go@v3 54 | # with: 55 | # go-version: 1.17 56 | # # Run linter 57 | # - name: Lint 58 | # run: make lint 59 | -------------------------------------------------------------------------------- /.github/workflows/release-docs.yml: -------------------------------------------------------------------------------- 1 | name: release-docs 2 | 3 | on: 4 | push: 5 | tags: 6 | - "*" 7 | 8 | jobs: 9 | build-docs: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout 13 | uses: actions/checkout@v4 14 | with: 15 | fetch-depth: 0 16 | submodules: true 17 | - name: Build Docs 18 | run: | 19 | make docs-build 20 | - name: Deploy 21 | uses: peaceiris/actions-gh-pages@v4 22 | with: 23 | github_token: ${{ secrets.GITHUB_TOKEN }} 24 | publish_dir: ./docs/book/book 25 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: goreleaser 2 | 3 | on: 4 | push: 5 | tags: 6 | - "*" 7 | 8 | jobs: 9 | goreleaser: 10 | runs-on: ubuntu-latest 11 | env: 12 | DOCKER_CLI_EXPERIMENTAL: "enabled" 13 | steps: 14 | - name: Checkout 15 | uses: actions/checkout@v4 16 | with: 17 | fetch-depth: 0 18 | submodules: true 19 | - name: Set up QEMU 20 | uses: docker/setup-qemu-action@v3 21 | - name: Set up Go 22 | uses: actions/setup-go@v5 23 | with: 24 | go-version: '1.22' 25 | - name: Login to DockerHub 26 | uses: docker/login-action@v3 27 | with: 28 | password: ${{secrets.DKR_TOKEN}} 29 | username: ${{secrets.DKR_USER}} 30 | # - name: Setup snapcraft 31 | # run: | 32 | # sudo snap install snapcraft --classic 33 | # echo "$SNAP_TOKEN" | snapcraft login --with - 34 | # env: 35 | # SNAP_TOKEN: ${{secrets.SNAP_LOGIN}} 36 | - name: Run GoReleaser 37 | uses: goreleaser/goreleaser-action@v5 38 | with: 39 | version: latest 40 | args: release --clean 41 | env: 42 | GITHUB_TOKEN: ${{ secrets.GH_PAT }} 43 | -------------------------------------------------------------------------------- /.github/workflows/titlecheck.yml: -------------------------------------------------------------------------------- 1 | name: titlecheck 2 | 3 | # Run on PR 4 | on: 5 | # enable for testing new changes 6 | # pull_request: 7 | pull_request_target: 8 | types: 9 | - opened 10 | - edited 11 | - synchronize 12 | - reopened 13 | 14 | jobs: 15 | titlecheck: 16 | name: PR title follows coventional commit 17 | runs-on: ubuntu-latest 18 | steps: 19 | - name: Check conventinal title 20 | uses: amannn/action-semantic-pull-request@v5 21 | env: 22 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # locally built binaries 2 | kconnect 3 | out/ 4 | 5 | # Test binary 6 | *.test 7 | 8 | # Output of the go coverage tool 9 | coverage.out 10 | 11 | # GoReleaser dist folder 12 | dist/ 13 | 14 | # Bin 15 | bin/ 16 | 17 | # Tools 18 | hack/tools/bin 19 | hack/tools/share 20 | 21 | # direnv files: 22 | .envrc 23 | 24 | # vim swp files 25 | *.swp 26 | 27 | .vscode/ 28 | .idea/ 29 | 30 | .DS_Store 31 | 32 | client_credentials.json 33 | 34 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fidelity/kconnect/fa47f0eae6c8683e1c4fc242ea78da73e367b434/.gitmodules -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | run: 2 | timeout: 10m 3 | tests: false 4 | 5 | issues: 6 | max-same-issues: 0 7 | max-issues-per-linter: 0 8 | exclude-rules: 9 | - linters: [golint] 10 | text: "should not use dot imports|don't use an underscore in package name" 11 | exclude-dirs: 12 | - third_party/* 13 | - pkg/azure/wstrust 14 | exclude-files: 15 | - "zz_generated.*\\.go$" 16 | - ".*_mock\\.go" 17 | 18 | linters-settings: 19 | gomoddirectives: 20 | # Allow local `replace` directives. 21 | replace-local: true 22 | # List of allowed `replace` directives. 23 | # Default: [] 24 | replace-allow-list: 25 | - github.com/spf13/cobra 26 | funlen: 27 | lines: 110 28 | statements: 60 29 | 30 | linters: 31 | fast: true 32 | enable-all: true 33 | disable: 34 | - cyclop 35 | - gochecknoglobals 36 | - gochecknoinits 37 | - lll 38 | - wsl 39 | - whitespace 40 | - godot 41 | - godox 42 | - nlreturn 43 | - gofumpt 44 | - gci 45 | - tagliatelle 46 | - interfacebloat 47 | - forcetypeassert # maybe enable in the future 48 | - depguard # maybe enable in the future 49 | -------------------------------------------------------------------------------- /.krew.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: krew.googlecontainertools.github.com/v1alpha2 2 | kind: Plugin 3 | metadata: 4 | name: connect 5 | spec: 6 | version: v{{ .TagName }} 7 | homepage: https://github.com/fidelity/kconnect 8 | shortDescription: "Discover and access clusters" 9 | description: | 10 | kconnect is a tool that can be used to discover and securely access Kubernetes 11 | clusters across multiple operating environments. 12 | Based on the authentication mechanism chosen the CLI will discover Kubernetes 13 | clusters you are allowed to access in a target hosting environment (i.e. EKS, AKS, Rancher) 14 | and generate a kubeconfig for a chosen cluster. 15 | Features: 16 | - Authenticate using SAML or Azure Active Directory 17 | - Discover EKS, AKS & Rancher clusters 18 | - Generate a kubeconfig for a cluster 19 | - Query history of connected servers 20 | - Regenerate the kubeconfig from your history by using an id or an alias 21 | - Import defaults values for your company 22 | caveats: | 23 | This plugin currently only supports EKS, AKS and Rancher 24 | platforms: 25 | - selector: 26 | matchLabels: 27 | os: linux 28 | arch: amd64 29 | {{addURIAndSha "https://github.com/fidelity/kconnect/releases/download/{{ .TagName }}/kconnect_linux_amd64.tar.gz" .TagName }} 30 | files: 31 | - from: "kconnect" 32 | to: "kubectl-connect" 33 | - from: "LICENSE" 34 | to: "." 35 | bin: kubectl-connect 36 | - selector: 37 | matchLabels: 38 | os: linux 39 | arch: arm64 40 | {{addURIAndSha "https://github.com/fidelity/kconnect/releases/download/{{ .TagName }}/kconnect_linux_arm64.tar.gz" .TagName }} 41 | files: 42 | - from: "kconnect" 43 | to: "kubectl-connect" 44 | - from: "LICENSE" 45 | to: "." 46 | bin: kubectl-connect 47 | - selector: 48 | matchLabels: 49 | os: darwin 50 | arch: amd64 51 | {{addURIAndSha "https://github.com/fidelity/kconnect/releases/download/{{ .TagName }}/kconnect_macos_amd64.tar.gz" .TagName }} 52 | files: 53 | - from: "kconnect" 54 | to: "kubectl-connect" 55 | - from: "LICENSE" 56 | to: "." 57 | bin: kubectl-connect 58 | - selector: 59 | matchLabels: 60 | os: darwin 61 | arch: arm64 62 | {{addURIAndSha "https://github.com/fidelity/kconnect/releases/download/{{ .TagName }}/kconnect_macos_amd64.tar.gz" .TagName }} 63 | files: 64 | - from: "kconnect" 65 | to: "kubectl-connect" 66 | - from: "LICENSE" 67 | to: "." 68 | bin: kubectl-connect 69 | - selector: 70 | matchLabels: 71 | os: windows 72 | arch: amd64 73 | {{addURIAndSha "https://github.com/fidelity/kconnect/releases/download/{{ .TagName }}/kconnect_windows_amd64.zip" .TagName }} 74 | files: 75 | - from: "kconnect.exe" 76 | to: "kubectl-connect.exe" 77 | - from: "LICENSE" 78 | to: "." 79 | bin: kubectl-connect.exe -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Community Code of Conduct 2 | 3 | kconnect follows the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md). 4 | 5 | Instances of abusive, harassing, or otherwise unacceptable behavior 6 | must be reported by contacting a _kconnect_ project maintainer. -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.20 AS certs 2 | RUN apk --update add ca-certificates && adduser -D kconnect 3 | 4 | FROM scratch 5 | 6 | COPY --from=certs /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt 7 | COPY kconnect / 8 | 9 | COPY --from=certs /etc/passwd /etc/passwd 10 | COPY --from=certs /home /home 11 | USER kconnect 12 | ENTRYPOINT ["/kconnect"] 13 | -------------------------------------------------------------------------------- /Dockerfile.alpine: -------------------------------------------------------------------------------- 1 | FROM alpine:3.20 2 | 3 | RUN apk --no-cache add ca-certificates && adduser -D kconnect 4 | COPY kconnect / 5 | 6 | USER kconnect 7 | ENTRYPOINT ["/kconnect"] 8 | -------------------------------------------------------------------------------- /Dockerfile.deps: -------------------------------------------------------------------------------- 1 | FROM alpine:3.20 AS builder 2 | 3 | ARG AWS_IAM_AUTH_VERSION=0.6.29 4 | ARG ODIC_LOGIN_VERSION=1.31.1 5 | ARG KUBELOGIN_VERSION=0.1.6 6 | ARG KUBECTL_VERSION=1.32.0 7 | ARG HELM_VERSION=3.16.4 8 | ARG TARGETOS 9 | ARG TARGETARCH 10 | ARG TARGETVARIANT 11 | 12 | RUN apk --no-cache add ca-certificates curl 13 | 14 | # kubectl 15 | RUN curl -LO "https://dl.k8s.io/release/v${KUBECTL_VERSION}/bin/${TARGETOS}/${TARGETARCH}/kubectl" && \ 16 | chmod +x ./kubectl 17 | 18 | # aws-iam-authenticator 19 | RUN curl -L \ 20 | https://github.com/kubernetes-sigs/aws-iam-authenticator/releases/download/v${AWS_IAM_AUTH_VERSION}/aws-iam-authenticator_${AWS_IAM_AUTH_VERSION}_${TARGETOS}_${TARGETARCH} -o aws-iam-authenticator && \ 21 | chmod +x ./aws-iam-authenticator 22 | 23 | # oidclogin 24 | RUN curl -L \ 25 | https://github.com/int128/kubelogin/releases/download/v${ODIC_LOGIN_VERSION}/kubelogin_${TARGETOS}_${TARGETARCH}.zip -o oidclogin.zip && \ 26 | unzip oidclogin.zip && \ 27 | mv kubelogin kubectl-oidc_login && \ 28 | chmod +x ./kubectl-oidc_login 29 | 30 | # kubelogin 31 | RUN curl -L \ 32 | https://github.com/Azure/kubelogin/releases/download/v${KUBELOGIN_VERSION}/kubelogin-${TARGETOS}-${TARGETARCH}.zip -o kubelogin.zip && \ 33 | unzip kubelogin.zip 34 | 35 | # Helm 36 | RUN curl -L https://get.helm.sh/helm-v${HELM_VERSION}-${TARGETOS}-${TARGETARCH}.tar.gz -o helm.tar.gz && \ 37 | tar xvfz helm.tar.gz 38 | 39 | FROM python:alpine 40 | 41 | WORKDIR /app/ 42 | ENV PATH="/app:${PATH}" 43 | ARG TARGETOS 44 | ARG TARGETARCH 45 | ARG TARGETVARIANT 46 | 47 | COPY --from=builder kubectl . 48 | COPY --from=builder aws-iam-authenticator . 49 | COPY --from=builder kubectl-oidc_login . 50 | COPY --from=builder bin/${TARGETOS}_${TARGETARCH}/kubelogin . 51 | COPY --from=builder ${TARGETOS}-${TARGETARCH}/helm . 52 | COPY kconnect . 53 | 54 | # Azure CLI 55 | RUN apk --no-cache add ca-certificates cargo gcc libffi-dev make musl-dev openssl-dev python3-dev && \ 56 | pip install --upgrade pip && \ 57 | pip install azure-cli && \ 58 | adduser -D kconnect 59 | USER kconnect 60 | ENTRYPOINT ["/app/kconnect"] 61 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # `kconnect` - The Kubernetes Connection Manager CLI 2 | 3 | ![GitHub issues](https://img.shields.io/github/issues/fidelity/kconnect) 4 | [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) 5 | [![Go Report Card](https://goreportcard.com/badge/github.com/fidelity/kconnect)](https://goreportcard.com/report/github.com/fidelity/kconnect) 6 | 7 | ## What is kconnect? 8 | 9 | kconnect is a CLI utility that can be used to discover and securely access Kubernetes clusters across multiple operating environments. 10 | 11 | Based on the authentication mechanism chosen the CLI will discover Kubernetes clusters you are allowed to access in a target hosting environment (i.e. EKS, AKS, Rancher) and generate a kubeconfig for a chosen cluster. 12 | 13 | **Currently supported platforms: EKS, AKS, Rancher** 14 | 15 | kconnect demo 16 | 17 | ## Features 18 | 19 | - Authenticate using SAML, Azure Active Directory, AWS IAM, Rancher Token 20 | - Discover clusters in EKS, AKS and Rancher 21 | - Generate a kubeconfig for a cluster 22 | - Query history of connected servers 23 | - Regenerate the kubeconfig from your history by using an id or an alias 24 | - Import defaults values for your company 25 | 26 | ## Documentation 27 | 28 | For installation, getting started and other documentation head over to the [projects documentation site](https://fidelity.github.io/kconnect/) or look in the [/docs](/docs) directory. 29 | 30 | ## Contributions 31 | 32 | Contributions are very welcome. Please read the [contributing guide](CONTRIBUTING.md) or see the docs. 33 | 34 | ## Acknowledgements 35 | 36 | For the SAML identity provider we rely heavily on the [saml2aws](https://github.com/Versent/saml2aws) project by Versent. For the Azure AD provider we have taken inspiration from the [Microsoft Authentication Library for Go](https://github.com/AzureAD/microsoft-authentication-library-for-go) and have directly used their wstrust package (see [pkg/azure/wstrust](pkg/azure/wstrust)). 37 | 38 | Thanks to both these projects for making the implementation easier. 39 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | The latest release will have security updates applied and a new path release 6 | made with the fixes. 7 | 8 | For example, if the current latest release is 0.3.1 and fix has been made due 9 | to a security issue then a new 0.3.2 release will be made with the fix 10 | 11 | ## Reporting a Vulnerability 12 | 13 | Please report security related issues by creating an new [issue](https://github.com/fidelity/kconnect/issues) 14 | -------------------------------------------------------------------------------- /api/v1alpha1/register.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Package v1alpha1 contains API Schema definitions for the iam v1alpha1 API group 18 | // +kubebuilder:object:generate=true 19 | // +groupName=kconnect.fidelity.github.com 20 | package v1alpha1 21 | 22 | import ( 23 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 24 | "k8s.io/apimachinery/pkg/runtime" 25 | "k8s.io/apimachinery/pkg/runtime/schema" 26 | "k8s.io/apimachinery/pkg/runtime/serializer" 27 | ) 28 | 29 | const ( 30 | GroupName = "kconnect.fidelity.github.com" 31 | ) 32 | 33 | var ( 34 | SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha1"} 35 | SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) 36 | localSchemeBuilder = &SchemeBuilder 37 | AddToScheme = localSchemeBuilder.AddToScheme 38 | ) 39 | 40 | func init() { 41 | localSchemeBuilder.Register(addKnownTypes) 42 | } 43 | 44 | func addKnownTypes(scheme *runtime.Scheme) error { 45 | scheme.AddKnownTypes(SchemeGroupVersion, 46 | &HistoryEntry{}, 47 | &HistoryEntryList{}, 48 | ) 49 | 50 | metav1.AddToGroupVersion( 51 | scheme, 52 | SchemeGroupVersion, 53 | ) 54 | 55 | return nil 56 | } 57 | 58 | func NewSchemeAndCodecs() (*runtime.Scheme, *serializer.CodecFactory, error) { 59 | scheme := runtime.NewScheme() 60 | if err := AddToScheme(scheme); err != nil { 61 | return nil, nil, err 62 | } 63 | codecs := serializer.NewCodecFactory(scheme) 64 | return scheme, &codecs, nil 65 | } 66 | -------------------------------------------------------------------------------- /cmd/kconnect/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "context" 21 | "fmt" 22 | "log" 23 | "os" 24 | "strconv" 25 | 26 | "go.uber.org/zap" 27 | 28 | "github.com/fidelity/kconnect/internal/commands" 29 | intver "github.com/fidelity/kconnect/internal/version" 30 | "github.com/fidelity/kconnect/pkg/flags" 31 | "github.com/fidelity/kconnect/pkg/logging" 32 | _ "github.com/fidelity/kconnect/pkg/plugins" // Import all the plugins 33 | ) 34 | 35 | func main() { 36 | if err := setupLogging(); err != nil { 37 | log.Fatalf("failed to configure logging %v", err) 38 | } 39 | 40 | v := intver.Get() 41 | zap.S().Infow("kconnect - the Kubernetes Connection Manager CLI", "version", v.Version) 42 | zap.S().Debugw("build information", "date", v.BuildDate, "commit", v.CommitHash, "gover", v.GoVersion) 43 | 44 | ctx := context.Background() 45 | rootCmd, err := commands.RootCmd() 46 | if err != nil { 47 | zap.S().Fatalw("failed getting root command", "error", err.Error()) 48 | } 49 | if err := rootCmd.ExecuteContext(ctx); err != nil { 50 | zap.S().Fatalw("failed executing root command", "error", err.Error()) 51 | } 52 | } 53 | 54 | func setupLogging() error { 55 | verbosity, err := flags.GetFlagValueDirect(os.Args, "verbosity", "v") 56 | if err != nil { 57 | return fmt.Errorf("getting verbosity flag: %w", err) 58 | } 59 | 60 | logVerbosity := 0 61 | if verbosity != "" { 62 | logVerbosity, err = strconv.Atoi(verbosity) 63 | if err != nil { 64 | return fmt.Errorf("parsing verbosity level: %w", err) 65 | } 66 | } 67 | 68 | if err := logging.Configure(logVerbosity); err != nil { 69 | log.Fatalf("failed to configure logging %v", err) 70 | } 71 | 72 | return nil 73 | } 74 | -------------------------------------------------------------------------------- /docs/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fidelity/kconnect/fa47f0eae6c8683e1c4fc242ea78da73e367b434/docs/.gitkeep -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # kconnect Documentation 2 | 3 | - [Initial Design](proposals/20200607-initial-design.md) 4 | - [CLI UX Proposal](proposals/20200630-cli-ux.md) 5 | -------------------------------------------------------------------------------- /docs/artefacts/hl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fidelity/kconnect/fa47f0eae6c8683e1c4fc242ea78da73e367b434/docs/artefacts/hl.png -------------------------------------------------------------------------------- /docs/artefacts/sequence.plantuml: -------------------------------------------------------------------------------- 1 | @startuml component 2 | autonumber 3 | actor User 4 | 5 | box "kconnect cli" #LightBlue 6 | participant "Discover Command" as DiscoverCmd 7 | participant "Generate Command" as GenerateCmd 8 | participant "Authentication Plugin" as AuthPlugin 9 | participant "Host Plugin" as HostPlug 10 | end box 11 | 12 | participant "Idp Server" as Idp 13 | participant "Discovery API" as DiscoApi 14 | collections Clusters 15 | 16 | == Discover Clusters == 17 | 18 | User -> DiscoverCmd: Discover clusters i have access to 19 | DiscoverCmd -> AuthPlugin: Authenticate me 20 | AuthPlugin -> Idp: Authenticate 21 | Idp -> AuthPlugin: Credentials 22 | AuthPlugin -> DiscoverCmd: Credentials 23 | loop for each host plugin 24 | DiscoverCmd->HostPlug: Get clusters 25 | activate HostPlug 26 | HostPlug -> AuthPlugin: Get credentials 27 | HostPlug -> DiscoApi: Get cluster list (with credentials) 28 | DiscoApi -> HostPlug: Cluster list 29 | HostPlug -> DiscoverCmd: Cluster list 30 | deactivate HostPlug 31 | end 32 | DiscoverCmd -> DiscoverCmd: Aggregate clusters 33 | DiscoverCmd -> User: Display clusters 34 | 35 | == Connect Clusters == 36 | 37 | User -> GenerateCmd: Generate kubeconfig for cluster X 38 | GenerateCmd -> HostPlug: Additional content 39 | HostPlug -> HostPlug: Generate kubeconfig 40 | alt additional files 41 | HostPlug -> HostPlug: Generate additional files 42 | end 43 | HostPlug -> User: Write files 44 | User -> Clusters: Connect to cluster 45 | 46 | @enduml -------------------------------------------------------------------------------- /docs/artefacts/sequence.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fidelity/kconnect/fa47f0eae6c8683e1c4fc242ea78da73e367b434/docs/artefacts/sequence.png -------------------------------------------------------------------------------- /docs/book/.gitignore: -------------------------------------------------------------------------------- 1 | book/ 2 | -------------------------------------------------------------------------------- /docs/book/book.toml: -------------------------------------------------------------------------------- 1 | [book] 2 | authors = ["The kconnect Maintainers"] 3 | language = "en" 4 | multilingual = false 5 | src = "src" 6 | title = "kconnect - The Kubernetes Connection Manager CLI" 7 | 8 | [output.html] 9 | curly-quotes = true 10 | git-repository-url = "https://github.com/fidelity/kconnect" 11 | -------------------------------------------------------------------------------- /docs/book/src/SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | - [Introduction](./introduction.md) 4 | - [Installation](./installation.md) 5 | - [Getting Started](./getting-started.md) 6 | - [Commands](./commands/index.md) 7 | - [alias](./commands/alias.md) 8 | - [add](./commands/alias_add.md) 9 | - [ls](./commands/alias_ls.md) 10 | - [remove](./commands/alias_remove.md) 11 | - [config](./commands/config.md) 12 | - [ls](./commands/ls.md) 13 | - [to](./commands/to.md) 14 | - [use](./commands/use.md) 15 | - [aks](./commands/use_aks.md) 16 | - [eks](./commands/use_eks.md) 17 | - [rancher](./commands/use_rancher.md) 18 | - [oidc](./commands/use_oidc.md) 19 | - [version](./commands/version.md) 20 | - [Releasing kconnect](./release.md) 21 | - [Contributing](./contributing.md) 22 | -------------------------------------------------------------------------------- /docs/book/src/commands/alias.md: -------------------------------------------------------------------------------- 1 | ## kconnect alias 2 | 3 | Query and manipulate connection history entry aliases. 4 | 5 | ### Synopsis 6 | 7 | 8 | An alias is a user-friendly name for a connection history entry, otherwise 9 | referred to by its entry ID. 10 | 11 | The alias command and sub-commands allow you to query and manipulate aliases for 12 | connection history entries. 13 | 14 | 15 | ```bash 16 | kconnect alias [flags] 17 | ``` 18 | 19 | ### Examples 20 | 21 | ```bash 22 | 23 | # Add an alias to an existing connection history entry 24 | kconnect alias add --id 123456 --alias appdev 25 | 26 | # List available connection history entry aliases 27 | kconnect alias ls 28 | 29 | # Remove an alias from a connection history entry 30 | kconnect alias remove --alias appdev 31 | 32 | ``` 33 | 34 | ### Options 35 | 36 | ```bash 37 | -h, --help help for alias 38 | --history-location string Location of where the history is stored. (default "$HOME/.kconnect/history.yaml") 39 | ``` 40 | 41 | ### Options inherited from parent commands 42 | 43 | ```bash 44 | --config string Configuration file for application wide defaults. (default "$HOME/.kconnect/config.yaml") 45 | --no-input Explicitly disable interactivity when running in a terminal 46 | --no-version-check If set to true kconnect will not check for a newer version 47 | -v, --verbosity int Sets the logging verbosity. Greater than 0 is debug and greater than 9 is trace. 48 | ``` 49 | 50 | ### SEE ALSO 51 | 52 | * [kconnect](index.md) - The Kubernetes Connection Manager CLI 53 | * [kconnect alias add](alias_add.md) - Add an alias to a connection history entry 54 | * [kconnect alias ls](alias_ls.md) - List all the aliases currently defined 55 | * [kconnect alias remove](alias_remove.md) - Remove connection history entry aliases. 56 | 57 | 58 | > NOTE: this page is auto-generated from the cobra commands 59 | -------------------------------------------------------------------------------- /docs/book/src/commands/alias_add.md: -------------------------------------------------------------------------------- 1 | ## kconnect alias add 2 | 3 | Add an alias to a connection history entry 4 | 5 | ### Synopsis 6 | 7 | 8 | Adds a user-friendly alias to a connection history entry. 9 | 10 | The user can then reconnect and refresh the access token for that cluster using 11 | the alias instead of the connection history entry's unique ID. 12 | 13 | 14 | ```bash 15 | kconnect alias add [flags] 16 | ``` 17 | 18 | ### Examples 19 | 20 | ```bash 21 | 22 | # Add an alias to a connection history entry 23 | kconnect alias add --id 01EMEM5DB60TMX7D8SS2JCX3MT --alias dev-bu-1 24 | 25 | # Connect to a cluster using the alias 26 | kconnect to dev-bu-1 27 | 28 | # List available aliases 29 | kconnect alias ls 30 | 31 | # List available history entries - includes aliases 32 | kconnect ls 33 | 34 | ``` 35 | 36 | ### Options 37 | 38 | ```bash 39 | --alias string Alias name for a history entry 40 | -h, --help help for add 41 | --id string Id for a history entry 42 | ``` 43 | 44 | ### Options inherited from parent commands 45 | 46 | ```bash 47 | --config string Configuration file for application wide defaults. (default "$HOME/.kconnect/config.yaml") 48 | --history-location string Location of where the history is stored. (default "$HOME/.kconnect/history.yaml") 49 | --no-input Explicitly disable interactivity when running in a terminal 50 | --no-version-check If set to true kconnect will not check for a newer version 51 | -v, --verbosity int Sets the logging verbosity. Greater than 0 is debug and greater than 9 is trace. 52 | ``` 53 | 54 | ### SEE ALSO 55 | 56 | * [kconnect alias](alias.md) - Query and manipulate connection history entry aliases. 57 | 58 | 59 | > NOTE: this page is auto-generated from the cobra commands 60 | -------------------------------------------------------------------------------- /docs/book/src/commands/alias_ls.md: -------------------------------------------------------------------------------- 1 | ## kconnect alias ls 2 | 3 | List all the aliases currently defined 4 | 5 | ### Synopsis 6 | 7 | 8 | List all the aliases currently defined for connection history entries in the 9 | user's connection history. 10 | 11 | An alias is a user-friendly name for a connection history entry. 12 | 13 | 14 | ```bash 15 | kconnect alias ls [flags] 16 | ``` 17 | 18 | ### Examples 19 | 20 | ```bash 21 | 22 | # Display all the aliases as a table 23 | kconnect alias ls 24 | 25 | # Display all connection history entry aliases as a table 26 | kconnect alias ls 27 | 28 | # Display all connection history entry aliases as json 29 | kconnect alias ls --output json 30 | 31 | # Connect to a cluster using a connection history entry alias 32 | kconnect to ${alias} 33 | 34 | # List all connection history entries as a table - includes aliases 35 | kconnect ls 36 | 37 | ``` 38 | 39 | ### Options 40 | 41 | ```bash 42 | -h, --help help for ls 43 | --output string Output format for the results (default "table") 44 | ``` 45 | 46 | ### Options inherited from parent commands 47 | 48 | ```bash 49 | --config string Configuration file for application wide defaults. (default "$HOME/.kconnect/config.yaml") 50 | --history-location string Location of where the history is stored. (default "$HOME/.kconnect/history.yaml") 51 | --no-input Explicitly disable interactivity when running in a terminal 52 | --no-version-check If set to true kconnect will not check for a newer version 53 | -v, --verbosity int Sets the logging verbosity. Greater than 0 is debug and greater than 9 is trace. 54 | ``` 55 | 56 | ### SEE ALSO 57 | 58 | * [kconnect alias](alias.md) - Query and manipulate connection history entry aliases. 59 | 60 | 61 | > NOTE: this page is auto-generated from the cobra commands 62 | -------------------------------------------------------------------------------- /docs/book/src/commands/alias_remove.md: -------------------------------------------------------------------------------- 1 | ## kconnect alias remove 2 | 3 | Remove connection history entry aliases. 4 | 5 | ### Synopsis 6 | 7 | 8 | Remove an alias from a single connection history entry by the entry ID or the 9 | alias. 10 | 11 | Set the --all flag on this command to remove all connection history aliases from 12 | the user's connection history. 13 | 14 | 15 | ```bash 16 | kconnect alias remove [flags] 17 | ``` 18 | 19 | ### Examples 20 | 21 | ```bash 22 | 23 | # Remove an alias using the alias name 24 | kconnect alias remove --alias dev-bu-1 25 | 26 | # Remove an alias using a histiry entry id 27 | kconnect alias remove --id 01EMEM5DB60TMX7D8SS2JCX3MT 28 | 29 | # Remove all aliases 30 | kconnect alias remove --all 31 | 32 | # List available aliases 33 | kconnect alias ls 34 | 35 | # Query your connection history - includes aliases 36 | kconnect ls 37 | 38 | ``` 39 | 40 | ### Options 41 | 42 | ```bash 43 | --alias string Alias name for a history entry 44 | --all Remove all aliases from the histiry entries 45 | -h, --help help for remove 46 | --id string Id for a history entry 47 | ``` 48 | 49 | ### Options inherited from parent commands 50 | 51 | ```bash 52 | --config string Configuration file for application wide defaults. (default "$HOME/.kconnect/config.yaml") 53 | --history-location string Location of where the history is stored. (default "$HOME/.kconnect/history.yaml") 54 | --no-input Explicitly disable interactivity when running in a terminal 55 | --no-version-check If set to true kconnect will not check for a newer version 56 | -v, --verbosity int Sets the logging verbosity. Greater than 0 is debug and greater than 9 is trace. 57 | ``` 58 | 59 | ### SEE ALSO 60 | 61 | * [kconnect alias](alias.md) - Query and manipulate connection history entry aliases. 62 | 63 | 64 | > NOTE: this page is auto-generated from the cobra commands 65 | -------------------------------------------------------------------------------- /docs/book/src/commands/config.md: -------------------------------------------------------------------------------- 1 | ## kconnect config 2 | 3 | Set and view your kconnect configuration. 4 | 5 | ### Synopsis 6 | 7 | 8 | The configure command creates kconnect configuration files and displays 9 | previously-defined configurations in a user-friendly display format. 10 | 11 | If run with no flags, the command displays the configurations stored in the 12 | current user's $HOME/.kconnect/config.yaml file. 13 | 14 | The configure command can create a set of default configurations for a new 15 | system or a new user via the -f flag and a local filename or remote URL. 16 | 17 | The user typically only needs to use this command the first time they use 18 | kconnect. 19 | 20 | 21 | ```bash 22 | kconnect config [flags] 23 | ``` 24 | 25 | ### Examples 26 | 27 | ```bash 28 | 29 | # Display user's current configurations 30 | kconnect config 31 | 32 | # Display the user's configurations as json 33 | kconnect config --output json 34 | 35 | # Set the user's configurations from a local file 36 | kconnect config -f ./defaults.yaml 37 | 38 | # Set the user's configurations from a remote location via HTTP 39 | kconnect config -f https://mycompany.com/config.yaml 40 | 41 | # Set the user's configurations from stdin 42 | cat ./config.yaml | kconnect config -f - 43 | 44 | ``` 45 | 46 | ### Options 47 | 48 | ```bash 49 | -f, --file string File or remote location to use to set the default configuration 50 | -h, --help help for config 51 | --output string Controls the output format for the result. (default "yaml") 52 | --password string The password used for authentication 53 | --username string The username used for authentication 54 | ``` 55 | 56 | ### Options inherited from parent commands 57 | 58 | ```bash 59 | --config string Configuration file for application wide defaults. (default "$HOME/.kconnect/config.yaml") 60 | --no-input Explicitly disable interactivity when running in a terminal 61 | --no-version-check If set to true kconnect will not check for a newer version 62 | -v, --verbosity int Sets the logging verbosity. Greater than 0 is debug and greater than 9 is trace. 63 | ``` 64 | 65 | ### SEE ALSO 66 | 67 | * [kconnect](index.md) - The Kubernetes Connection Manager CLI 68 | 69 | 70 | > NOTE: this page is auto-generated from the cobra commands 71 | -------------------------------------------------------------------------------- /docs/book/src/commands/history.md: -------------------------------------------------------------------------------- 1 | ## kconnect history 2 | 3 | Import and export history 4 | 5 | ### Synopsis 6 | 7 | 8 | Command to allow users to import or export history files. 9 | 10 | A common use case would be for one member of a team to generate the history + 11 | alias config for their teams cluster(s). They could then send this file out to 12 | the rest of the team, who can then import it. On import, they can set their 13 | username for all of the history entries. 14 | 15 | 16 | ```bash 17 | kconnect history [flags] 18 | ``` 19 | 20 | ### Examples 21 | 22 | ```bash 23 | 24 | # Export all history entries that have alias = *dev* 25 | kconnect history export -f history.yaml --filter alias=*dev* 26 | 27 | # Import history entries and set username 28 | kconnect history import -f history.yaml --set username=myuser 29 | 30 | ``` 31 | 32 | ### Options 33 | 34 | ```bash 35 | -h, --help help for history 36 | --history-location string Location of where the history is stored. (default "$HOME/.kconnect/history.yaml") 37 | ``` 38 | 39 | ### Options inherited from parent commands 40 | 41 | ```bash 42 | --config string Configuration file for application wide defaults. (default "$HOME/.kconnect/config.yaml") 43 | --no-input Explicitly disable interactivity when running in a terminal 44 | --no-version-check If set to true kconnect will not check for a newer version 45 | -v, --verbosity int Sets the logging verbosity. Greater than 0 is debug and greater than 9 is trace. 46 | ``` 47 | 48 | ### SEE ALSO 49 | 50 | * [kconnect](index.md) - The Kubernetes Connection Manager CLI 51 | * [kconnect history export](history_export.md) - Export history to an external file 52 | * [kconnect history import](history_import.md) - Import history from an external file 53 | * [kconnect history rm](history_rm.md) - Remove history entries 54 | 55 | 56 | > NOTE: this page is auto-generated from the cobra commands 57 | -------------------------------------------------------------------------------- /docs/book/src/commands/history_export.md: -------------------------------------------------------------------------------- 1 | ## kconnect history export 2 | 3 | Export history to an external file 4 | 5 | ### Synopsis 6 | 7 | 8 | Allows users to export history to an external file. This file can then be 9 | imported by another user using the import command" 10 | 11 | 12 | ```bash 13 | kconnect history export [flags] 14 | ``` 15 | 16 | ### Examples 17 | 18 | ```bash 19 | 20 | # Export your history into a file 21 | kconnect history export -f exportfile.yaml 22 | 23 | # Set username and namespace for exported entries 24 | kconnect history export -f exportfile.yaml --set username=MYUSER,namespace=kube-system 25 | 26 | # Only export entries that match filter 27 | kconnect history export -f exportfile.yaml --filter region=us-east-1,alias=*dev* 28 | 29 | ``` 30 | 31 | ### Options 32 | 33 | ```bash 34 | -f, --file string file to import 35 | --filter string filter to apply to import. Can specify multiple filters by using commas, and supports wilcards (*) 36 | -h, --help help for export 37 | --set string fields to set 38 | ``` 39 | 40 | ### Options inherited from parent commands 41 | 42 | ```bash 43 | --config string Configuration file for application wide defaults. (default "$HOME/.kconnect/config.yaml") 44 | --history-location string Location of where the history is stored. (default "$HOME/.kconnect/history.yaml") 45 | --no-input Explicitly disable interactivity when running in a terminal 46 | --no-version-check If set to true kconnect will not check for a newer version 47 | -v, --verbosity int Sets the logging verbosity. Greater than 0 is debug and greater than 9 is trace. 48 | ``` 49 | 50 | ### SEE ALSO 51 | 52 | * [kconnect history](history.md) - Import and export history 53 | 54 | 55 | > NOTE: this page is auto-generated from the cobra commands 56 | -------------------------------------------------------------------------------- /docs/book/src/commands/history_import.md: -------------------------------------------------------------------------------- 1 | ## kconnect history import 2 | 3 | Import history from an external file 4 | 5 | ### Synopsis 6 | 7 | 8 | Allows users to import history from an external file. This can then be viewed 9 | using the ls command, or connected to using the to command. 10 | 11 | These imported entries will be merged with existing ones. If there is a 12 | conflict, then the conflicting entry will not be imported (unless 13 | --overwrite flag is supplied). 14 | 15 | Users can optionally set any fields in the imported entry 16 | 17 | 18 | ```bash 19 | kconnect history import [flags] 20 | ``` 21 | 22 | ### Examples 23 | 24 | ```bash 25 | 26 | # Imports the file into your history 27 | kconnect history import -f importfile.yaml 28 | 29 | # Overwrite conflicting entries 30 | kconnect history import -f importfile.yaml --overwrite 31 | 32 | # Wipe existing history 33 | kconnect history import -f importfile.yaml --clean 34 | 35 | # Set username and namespace for imported entries 36 | kconnect history import -f importfile.yaml --set username=MYUSER,namespace=kube-system 37 | 38 | # Only import entries that match filter 39 | kconnect history import -f importfile.yaml --filter region=us-east-1,alias=*dev* 40 | 41 | ``` 42 | 43 | ### Options 44 | 45 | ```bash 46 | --clean delete all existing history 47 | -f, --file string File to import 48 | --filter string filter to apply to import 49 | -h, --help help for import 50 | --overwrite overwrite conflicting entries 51 | --set string fields to set 52 | ``` 53 | 54 | ### Options inherited from parent commands 55 | 56 | ```bash 57 | --config string Configuration file for application wide defaults. (default "$HOME/.kconnect/config.yaml") 58 | --history-location string Location of where the history is stored. (default "$HOME/.kconnect/history.yaml") 59 | --no-input Explicitly disable interactivity when running in a terminal 60 | --no-version-check If set to true kconnect will not check for a newer version 61 | -v, --verbosity int Sets the logging verbosity. Greater than 0 is debug and greater than 9 is trace. 62 | ``` 63 | 64 | ### SEE ALSO 65 | 66 | * [kconnect history](history.md) - Import and export history 67 | 68 | 69 | > NOTE: this page is auto-generated from the cobra commands 70 | -------------------------------------------------------------------------------- /docs/book/src/commands/history_rm.md: -------------------------------------------------------------------------------- 1 | ## kconnect history rm 2 | 3 | Remove history entries 4 | 5 | ### Synopsis 6 | 7 | 8 | Allows users to delete history entries from their history 9 | 10 | 11 | ```bash 12 | kconnect history rm [flags] 13 | ``` 14 | 15 | ### Examples 16 | 17 | ```bash 18 | 19 | # Display history entries 20 | kconnect ls 21 | 22 | # Delete a history entry with specific ID 23 | kconnect history rm 01exm3ty400w9sr28jawc8fkae 24 | 25 | # Delete multiple history entries with specific IDs 26 | kconnect history rm 01exm3ty400w9sr28jawc8fkae 01exm3tvw2f5snkj18rk1ngmyb 27 | 28 | # Delete all history entries 29 | kconnect history rm --all 30 | 31 | # Delete all history entries that match the filter (e.g. alias that have "prod" in them) 32 | kconnect history rm --filter alias=*prod* 33 | 34 | ``` 35 | 36 | ### Options 37 | 38 | ```bash 39 | --all remove all entries 40 | --filter string filter to apply to import. Can specify multiple filters by using commas, and supports wilcards (*) 41 | -h, --help help for rm 42 | ``` 43 | 44 | ### Options inherited from parent commands 45 | 46 | ```bash 47 | --config string Configuration file for application wide defaults. (default "$HOME/.kconnect/config.yaml") 48 | --history-location string Location of where the history is stored. (default "$HOME/.kconnect/history.yaml") 49 | --no-input Explicitly disable interactivity when running in a terminal 50 | --no-version-check If set to true kconnect will not check for a newer version 51 | -v, --verbosity int Sets the logging verbosity. Greater than 0 is debug and greater than 9 is trace. 52 | ``` 53 | 54 | ### SEE ALSO 55 | 56 | * [kconnect history](history.md) - Import and export history 57 | 58 | 59 | > NOTE: this page is auto-generated from the cobra commands 60 | -------------------------------------------------------------------------------- /docs/book/src/commands/logout.md: -------------------------------------------------------------------------------- 1 | ## kconnect logout 2 | 3 | Logs out of a cluster 4 | 5 | ### Synopsis 6 | 7 | 8 | Logs out of a cluster. Can logout of specific cluster by their alias or entry ID. 9 | Log out of all clusters by using the --all flag 10 | If neither above options are selected, will log out of current cluster 11 | 12 | 13 | ```bash 14 | kconnect logout [flags] 15 | ``` 16 | 17 | ### Options 18 | 19 | ```bash 20 | --alias string comma delimited list of aliass 21 | -a, --all Logs out of all clusters 22 | -h, --help help for logout 23 | --history-location string Location of where the history is stored. (default "$HOME/.kconnect/history.yaml") 24 | --ids string comma delimited list of ids 25 | -k, --kubeconfig string Location of the kubeconfig to use. (default "$HOME/.kube/config") 26 | ``` 27 | 28 | ### Options inherited from parent commands 29 | 30 | ```bash 31 | --config string Configuration file for application wide defaults. (default "$HOME/.kconnect/config.yaml") 32 | --no-input Explicitly disable interactivity when running in a terminal 33 | --no-version-check If set to true kconnect will not check for a newer version 34 | -v, --verbosity int Sets the logging verbosity. Greater than 0 is debug and greater than 9 is trace. 35 | ``` 36 | 37 | ### SEE ALSO 38 | 39 | * [kconnect](index.md) - The Kubernetes Connection Manager CLI 40 | 41 | 42 | > NOTE: this page is auto-generated from the cobra commands 43 | -------------------------------------------------------------------------------- /docs/book/src/commands/ls.md: -------------------------------------------------------------------------------- 1 | ## kconnect ls 2 | 3 | Query the user's connection history 4 | 5 | ### Synopsis 6 | 7 | 8 | Query and display the user's connection history entries, including entry IDs and 9 | aliases. 10 | 11 | Each time kconnect creates a new kubectl context to connect to a Kubernetes 12 | cluster, it saves the settings for the new connection as an entry in the user's 13 | connection history. The user can then reconnect using those same settings later 14 | via the connection history entry's ID or alias. 15 | 16 | 17 | ```bash 18 | kconnect ls [flags] 19 | ``` 20 | 21 | ### Examples 22 | 23 | ```bash 24 | 25 | # Display all connection history entries as a table 26 | kconnect ls 27 | 28 | # Display all connection history entries as YAML 29 | kconnect ls --output yaml 30 | 31 | # Display a specific connection history entry by entry id 32 | kconnect ls --filter id=01EM615GB2YX3C6WZ9MCWBDWBF 33 | 34 | # Display a specific connection history entry by its alias 35 | kconnect ls --filter alias=mydev 36 | 37 | # Display all connection history entries that have "dev" in its alias 38 | kconnect ls --filter alias=*dev* 39 | 40 | # Display all connection history entries for the EKS managed cluster provider 41 | kconnect ls --filter cluster-provider=eks 42 | 43 | # Display all connection history entries for entries with namespace kube-system 44 | kconnect ls --filter namespace=kube-system 45 | 46 | # Reconnect using the connection history entry alias 47 | kconnect to mydev 48 | 49 | ``` 50 | 51 | ### Options 52 | 53 | ```bash 54 | --filter string filter to apply to import. Can specify multiple filters by using commas, and supports wilcards (*) 55 | -h, --help help for ls 56 | --history-location string Location of where the history is stored. (default "$HOME/.kconnect/history.yaml") 57 | -k, --kubeconfig string Location of the kubeconfig to use. (default "$HOME/.kube/config") 58 | --max-history int Sets the maximum number of history items to keep (default 100) 59 | --no-history If set to true then no history entry will be written 60 | -o, --output string Output format for the results (default "table") 61 | ``` 62 | 63 | ### Options inherited from parent commands 64 | 65 | ```bash 66 | --config string Configuration file for application wide defaults. (default "$HOME/.kconnect/config.yaml") 67 | --no-input Explicitly disable interactivity when running in a terminal 68 | --no-version-check If set to true kconnect will not check for a newer version 69 | -v, --verbosity int Sets the logging verbosity. Greater than 0 is debug and greater than 9 is trace. 70 | ``` 71 | 72 | ### SEE ALSO 73 | 74 | * [kconnect](index.md) - The Kubernetes Connection Manager CLI 75 | 76 | 77 | > NOTE: this page is auto-generated from the cobra commands 78 | -------------------------------------------------------------------------------- /docs/book/src/commands/to.md: -------------------------------------------------------------------------------- 1 | ## kconnect to 2 | 3 | Reconnect to a connection history entry. 4 | 5 | ### Synopsis 6 | 7 | 8 | Reconnect to a cluster in the connection history by its entry ID or alias. 9 | 10 | The kconnect tool creates an entry in the user's connection history with all the 11 | connection settings each time it generates a new kubectl configuration context 12 | for a Kubernetes cluster. The user can then reconnect to the same cluster and 13 | refresh their access token or regenerate the kubectl configuration context using 14 | the connection history entry's ID or alias. 15 | 16 | The to command also accepts - or LAST as proxy references to the most recent 17 | connection history entry, or LAST~N for the Nth previous entry. 18 | 19 | Although kconnect does not save the user's password in the connection history, 20 | the user can avoid having to enter their password interactively by setting the 21 | KCONNECT_PASSWORD environment variable or the --password command-line flag. 22 | Otherwise kconnect will promot the user to enter their password. 23 | 24 | 25 | ```bash 26 | kconnect to [historyid/alias/-/LAST/LAST~N] [flags] 27 | ``` 28 | 29 | ### Examples 30 | 31 | ```bash 32 | 33 | # Reconnect based on an alias - aliases can be found using kconnect ls 34 | kconnect to uat-bu1 35 | 36 | # Reconnect based on an history id - history id can be found using kconnect ls 37 | kconnect to 01EM615GB2YX3C6WZ9MCWBDWBF 38 | 39 | # Reconnect interactively from history list 40 | kconnect to 41 | 42 | # Reconnect to current cluster (this is useful for renewing credentials) 43 | kconnect to - 44 | OR 45 | kconnect to LAST 46 | 47 | # Reconnect to cluster used before current one 48 | kconnect to LAST~1 49 | 50 | # Reconnect based on an alias supplying a password 51 | kconnect to uat-bu1 --password supersecret 52 | 53 | # Reconnect based on an alias supplying a password via env var 54 | KCONNECT_PASSWORD=supersecret kconnect to uat-bu2 55 | 56 | ``` 57 | 58 | ### Options 59 | 60 | ```bash 61 | -h, --help help for to 62 | --history-location string Location of where the history is stored. (default "$HOME/.kconnect/history.yaml") 63 | -k, --kubeconfig string Location of the kubeconfig to use. (default "$HOME/.kube/config") 64 | --password string Password to use 65 | --set-current Sets the current context in the kubeconfig to the selected cluster (default true) 66 | ``` 67 | 68 | ### Options inherited from parent commands 69 | 70 | ```bash 71 | --config string Configuration file for application wide defaults. (default "$HOME/.kconnect/config.yaml") 72 | --no-input Explicitly disable interactivity when running in a terminal 73 | --no-version-check If set to true kconnect will not check for a newer version 74 | -v, --verbosity int Sets the logging verbosity. Greater than 0 is debug and greater than 9 is trace. 75 | ``` 76 | 77 | ### SEE ALSO 78 | 79 | * [kconnect](index.md) - The Kubernetes Connection Manager CLI 80 | 81 | 82 | > NOTE: this page is auto-generated from the cobra commands 83 | -------------------------------------------------------------------------------- /docs/book/src/commands/version.md: -------------------------------------------------------------------------------- 1 | ## kconnect version 2 | 3 | Display version & build information 4 | 5 | ### Synopsis 6 | 7 | Display version & build information 8 | 9 | ```bash 10 | kconnect version [flags] 11 | ``` 12 | 13 | ### Options 14 | 15 | ```bash 16 | -h, --help help for version 17 | ``` 18 | 19 | ### Options inherited from parent commands 20 | 21 | ```bash 22 | --config string Configuration file for application wide defaults. (default "$HOME/.kconnect/config.yaml") 23 | --no-input Explicitly disable interactivity when running in a terminal 24 | --no-version-check If set to true kconnect will not check for a newer version 25 | -v, --verbosity int Sets the logging verbosity. Greater than 0 is debug and greater than 9 is trace. 26 | ``` 27 | 28 | ### SEE ALSO 29 | 30 | * [kconnect](index.md) - The Kubernetes Connection Manager CLI 31 | 32 | 33 | > NOTE: this page is auto-generated from the cobra commands 34 | -------------------------------------------------------------------------------- /docs/book/src/contributing.md: -------------------------------------------------------------------------------- 1 | {{#include ../../../CONTRIBUTING.md:2:}} 2 | -------------------------------------------------------------------------------- /docs/book/src/getting-started.md: -------------------------------------------------------------------------------- 1 | # Getting started 2 | 3 | Once you have [installed](installation.md) kconnect you can see a list of the commands available by running: 4 | 5 | ```bash 6 | kconnect help 7 | ``` 8 | 9 | NOTE: `kconnect` requires: 10 | * [aws-iam-authenticator](https://github.com/kubernetes-sigs/aws-iam-authenticator) to authenticate to AWS EKS clusters. 11 | * [kubelogin](https://github.com/Azure/kubelogin) to authenticate to Azure AKS clusters. 12 | 13 | The general workflow for using kconnect is the following: 14 | 15 | - `kconnect configure` - import configuration that contains defaults for your organisation - **1 time** 16 | - `kconnect use` - connect to a cluster for the first time - **only the first time** 17 | - `kconnect to` - use to reconnect to a cluster that you have already connected to - **most used command day-to-day** 18 | 19 | ## Creating and importing configuration 20 | 21 | Before using `kconnect` to connect to a Kubernetes cluster you may want to import an identity provider configuration with your (or your organisations) defaults so that you don't have to supply all connection settings each time you connect to a new cluster. 22 | 23 | You will need to create a configuration file (see example [here](https://github.com/fidelity/kconnect/blob/main/examples/config.yaml)). The configuration file can be imported from a local file or remote location via HTTP/HTTPS (and from stdin). 24 | 25 | Each new user in your organization can then import the default configurations in this file using the `kconnect configure` command with the `-f` flag: 26 | 27 | ```bash 28 | kconnect configure -f https://raw.githubusercontent.com/fidelity/kconnect/main/examples/config.yaml 29 | ``` 30 | 31 | Once the user has created their local configuration file, they should be able to display their configuration settings. 32 | 33 | ```bash 34 | kconnect configure 35 | ``` 36 | 37 | ## First time connection to a cluster 38 | 39 | When discovering and connecting to a cluster for the first time you can do the following: 40 | 41 | ```bash 42 | kconnect use eks --idp-protocol saml 43 | ``` 44 | 45 | This will guide you interactively setting the flags and selecting a cluster. It also gives you the option to set an easy-to-remember alias. 46 | 47 | NOTE: only saml is supported at present for IdP. 48 | 49 | ## Reconnecting to a cluster 50 | 51 | If you've previously connected to a cluster you can reconnect to it using the alias (if you set one): 52 | 53 | ```bash 54 | kconnect to dev-bu-1 55 | ``` 56 | 57 | Or using the history id (which can be found by using `kconnect ls`): 58 | 59 | ```bash 60 | kconnect to 01EM615GB2YX3C6WZ9MCWBDWBF 61 | ``` 62 | 63 | ## Setting Flags 64 | 65 | Flags can be replaced with environment variables by following the format `UPPERCASED_SNAKE_CASE` and appending to the `KCONNECT_` prefix. 66 | 67 | For example `--username` can be set as `KCONNECT_USERNAME`; or `--idp-protocol` as `KCONNECT_IDP_PROTOCOL`. 68 | -------------------------------------------------------------------------------- /docs/book/src/images/kconnectfrontpage.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fidelity/kconnect/fa47f0eae6c8683e1c4fc242ea78da73e367b434/docs/book/src/images/kconnectfrontpage.gif -------------------------------------------------------------------------------- /docs/book/src/installation.md: -------------------------------------------------------------------------------- 1 | # Installation 2 | 3 | - [Mac OSX](#mac) 4 | - [Linux](#linux) 5 | - [Windows](#windows) 6 | - [Docker](#docker) 7 | 8 | NOTE: `kconnect` requires [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl) for k8s cluster cli interaction. 9 | 10 | NOTE: `kconnect` requires [aws-iam-authenticator](https://github.com/kubernetes-sigs/aws-iam-authenticator) for authentication to AWS EKS clusters. 11 | 12 | NOTE: `kconnect` requires [kubelogin](https://github.com/Azure/kubelogin) for non-interactive authentication to Azure AKS clusters. 13 | 14 | NOTE: `kconnect` requires [az cli](https://github.com/Azure/azure-cli) for interactive authentication to Azure AKS clusters. 15 | 16 | NOTE:> For specific tested and pinned versions, use the `install-kconnect.sh` script or the `with-deps` docker image 17 | 18 | ## kubectl plugin 19 | 20 | To install as a kubectl plugin: 21 | 22 | ```bash 23 | kubectl krew index add fidelity https://github.com/fidelity/krew-index.git 24 | kubectl krew install fidelity/connect 25 | ``` 26 | 27 | You can then run like so: 28 | ```bash 29 | kubectl connect use eks 30 | ``` 31 | 32 | ## Mac 33 | 34 | To install on OSX you can use homebrew: 35 | 36 | ```bash 37 | brew install fidelity/tap/kconnect 38 | ``` 39 | 40 | Alternatively you can download a binary from the latest [release](https://github.com/fidelity/kconnect/releases). 41 | 42 | ## Linux 43 | 44 | To install on Linux you can use homebrew: 45 | 46 | ```bash 47 | brew install fidelity/tap/kconnect 48 | ``` 49 | 50 | Alternatively, the latest [release](https://github.com/fidelity/kconnect/releases) contains **.deb**, **.rpm** and binaries for Linux. 51 | 52 | We are working on publishing as a snap. 53 | 54 | ## Windows 55 | 56 | The latest [release](https://github.com/fidelity/kconnect/releases) contains a binary for Windows. 57 | 58 | We have an open issue to support chocolatey in the future. 59 | 60 | ## Docker 61 | 62 | You can also use kconnect via Docker by using the images we publish to Docker Hub: 63 | 64 | ```bash 65 | docker pull docker.io/kconnectcli/kconnect:latest 66 | docker run -it --rm -v ~/.kconnect:/.kconnect kconnect:latest use eks --idp-protocol saml 67 | ``` 68 | ## Install script 69 | 70 | You can install kconnect, along with kubectl, helm and aws-iam-authenticator by running: 71 | 72 | ```bash 73 | curl -fsSL -o install-kconnect.sh https://raw.githubusercontent.com/fidelity/kconnect/main/scripts/install-kconnect.sh 74 | chmod 700 install-kconnect.sh 75 | ./install-kconnect.sh 76 | ``` 77 | 78 | This works on Linux, macOS and Windows (using GitBash terminal) 79 | -------------------------------------------------------------------------------- /docs/book/src/introduction.md: -------------------------------------------------------------------------------- 1 | {{#include ../../../README.md:2:}} 2 | -------------------------------------------------------------------------------- /docs/book/src/release.md: -------------------------------------------------------------------------------- 1 | # Releasing kconnect 2 | 3 | The release of *kconnect* is done using [goreleaser](https://goreleaser.com/) which is orchestrated using Githib Actions. 4 | 5 | ## Process 6 | 7 | The following steps are required to do a release: 8 | 9 | 1. Merge any PRs into the **main** branch that contain features, bug fixes and other changes that you want to include in the release. 10 | 2. We use [Semver 2.0](https://semver.org/) for the release numbering. You will need to decide what the next release number will be based on the changes and whether it will be a *"pre-release"*: 11 | * *Normal release*: it will follow the MAJOR.MINOR.PATCH format, for example 0.3.0 12 | * *Pre-release*: it will follow the MAJOR.MINOR.PATCH-rc.RCNUMBER format, for example 0.3.0-rc.1 13 | 3. Locally on your machine get the latest **main** branch code: 14 | ```bash 15 | git checkout main 16 | git pull 17 | ``` 18 | 4. Tag the main branch with the release number previously determined: 19 | ```bash 20 | git tag -a 0.3.0 -m "0.3.0" 21 | ``` 22 | 5. Push the new tag to GitHub: 23 | ```bash 24 | git push origin 0.3.0 25 | ``` 26 | 6. Go to GitHub and check on the **goreleaser** [action](https://github.com/fidelity/kconnect/actions?query=workflow%3Agoreleaser). This action is what does the actual release. 27 | 7. Once the **goreleaser** action completes go to the [releases on GitHub](https://github.com/fidelity/kconnect/releases) and check the release is available. 28 | 8. Click **Edit** next to the release and tidy up the **Changelog** entries. If there are any breaking changes then a new markdown section should be added to the top that documents this. 29 | 9. Locally on your machine, run this command: 30 | ```bash 31 | sudo docker run -v /path/to/repo/.krew.yaml:/tmp/template-file.yaml rajatjindal/krew-release-bot:v0.0.38 krew-release-bot template --tag 0.3.0 --template-file /tmp/template-file.yaml 32 | ``` 33 | 10. Take the output of this command (excluding logging output). Update this file https://github.com/fidelity/krew-index/blob/main/plugins/connect.yaml with the output you just obtained (note: these manual steps will be automated in future) 34 | 35 | ## Implementation 36 | 37 | We use [goreleaser](https://goreleaser.com/) to do the majority of the build, packaging and release. The [.goreleaser.yml](https://github.com/fidelity/kconnect/blob/main/.goreleaser.yml) configuration file drives this. 38 | 39 | The **goreleaser** GitHub Action that kicks off goreleaser on tagging the main branch is located [here](https://github.com/fidelity/kconnect/blob/main/.github/workflows/release.yml). 40 | 41 | There is an additional GitHub workflow that is used to publish the docs to GitHub pages and that is located [here](https://github.com/fidelity/kconnect/blob/main/.github/workflows/release-docs.yml). 42 | 43 | -------------------------------------------------------------------------------- /docs/book/theme/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fidelity/kconnect/fa47f0eae6c8683e1c4fc242ea78da73e367b434/docs/book/theme/favicon.png -------------------------------------------------------------------------------- /docs/book/theme/head.hbs: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /docs/proposals/YYYYMMDD-template.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: proposal Template 3 | authors: 4 | - "@joebloggs" 5 | reviewers: 6 | - "@joebloggs" 7 | creation-date: yyyy-mm-dd 8 | last-updated: yyyy-mm-dd 9 | status: provisional|experimental|implementable|implemented|deferred|rejected|withdrawn|replaced 10 | see-also: 11 | - "/docs/proposals/20190101-we-heard-you-like-proposals.md" 12 | replaces: 13 | - "/docs/proposals/20181231-replaced-proposal.md" 14 | superseded-by: 15 | - "/docs/proposals/20190104-superceding-proposal.md" 16 | --- 17 | 18 | # Title 19 | 20 | ## Summary 21 | 22 | A brief summary of the proposal/change 23 | 24 | ## Motivation 25 | 26 | Why is this change needed 27 | 28 | ### Goals 29 | 30 | * List of specific goals for the proposal 31 | 32 | ### Non-goals/Future Work 33 | 34 | * List what is out of scope 35 | 36 | ## Proposal/Design 37 | 38 | The main section of the proposal/design 39 | 40 | ### User Stories 41 | 42 | #### Story 1 43 | 44 | As an XXXX, i want to XXXXX, so that i can XXXXX. 45 | 46 | ### Implementation Details/Notes/Constraints 47 | 48 | Any important details not covered above 49 | 50 | ### Risks and Mitigation 51 | 52 | List any risk associated with this change and how they can be mitigated 53 | 54 | ### Upgrade Strategy 55 | 56 | Detail the upgrade strategy if its applicable 57 | 58 | ### Additional Details 59 | 60 | Add anything else relevant here 61 | -------------------------------------------------------------------------------- /examples/config.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kconnect.fidelity.github.com/v1alpha1 2 | kind: Configuration 3 | spec: 4 | global: 5 | username: alice@test.com 6 | providers: 7 | eks: 8 | region: eu-west-2 9 | username: bob@test.com 10 | -------------------------------------------------------------------------------- /hack/boilerplate.generatego.txt: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | -------------------------------------------------------------------------------- /hack/tools/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/fidelity/kconnect/hack/tools 2 | 3 | go 1.17 4 | 5 | require ( 6 | github.com/golang/mock v1.6.0 7 | k8s.io/code-generator v0.33.0 8 | sigs.k8s.io/controller-tools v0.17.3 9 | ) 10 | 11 | require ( 12 | github.com/emicklei/go-restful/v3 v3.11.0 // indirect 13 | github.com/fatih/color v1.18.0 // indirect 14 | github.com/fxamacker/cbor/v2 v2.7.0 // indirect 15 | github.com/go-logr/logr v1.4.2 // indirect 16 | github.com/go-openapi/jsonpointer v0.21.0 // indirect 17 | github.com/go-openapi/jsonreference v0.20.2 // indirect 18 | github.com/go-openapi/swag v0.23.0 // indirect 19 | github.com/gobuffalo/flect v1.0.3 // indirect 20 | github.com/gogo/protobuf v1.3.2 // indirect 21 | github.com/google/gnostic-models v0.6.9 // indirect 22 | github.com/inconshreveable/mousetrap v1.1.0 // indirect 23 | github.com/josharian/intern v1.0.0 // indirect 24 | github.com/json-iterator/go v1.1.12 // indirect 25 | github.com/mailru/easyjson v0.7.7 // indirect 26 | github.com/mattn/go-colorable v0.1.13 // indirect 27 | github.com/mattn/go-isatty v0.0.20 // indirect 28 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 29 | github.com/modern-go/reflect2 v1.0.2 // indirect 30 | github.com/spf13/cobra v1.9.1 // indirect 31 | github.com/spf13/pflag v1.0.6 // indirect 32 | github.com/x448/float16 v0.8.4 // indirect 33 | golang.org/x/mod v0.23.0 // indirect 34 | golang.org/x/net v0.38.0 // indirect 35 | golang.org/x/sync v0.12.0 // indirect 36 | golang.org/x/sys v0.31.0 // indirect 37 | golang.org/x/text v0.23.0 // indirect 38 | golang.org/x/tools v0.30.0 // indirect 39 | google.golang.org/protobuf v1.36.5 // indirect 40 | gopkg.in/inf.v0 v0.9.1 // indirect 41 | gopkg.in/yaml.v2 v2.4.0 // indirect 42 | gopkg.in/yaml.v3 v3.0.1 // indirect 43 | k8s.io/api v0.32.2 // indirect 44 | k8s.io/apiextensions-apiserver v0.32.2 // indirect 45 | k8s.io/apimachinery v0.33.0 // indirect 46 | k8s.io/gengo/v2 v2.0.0-20250207200755-1244d31929d7 // indirect 47 | k8s.io/klog/v2 v2.130.1 // indirect 48 | k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect 49 | k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect 50 | sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect 51 | sigs.k8s.io/randfill v1.0.0 // indirect 52 | sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect 53 | sigs.k8s.io/yaml v1.4.0 // indirect 54 | ) 55 | -------------------------------------------------------------------------------- /hack/tools/tools.go: -------------------------------------------------------------------------------- 1 | // +build tools 2 | 3 | /* 4 | Copyright 2020 The kconnect Authors. 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | // This package is used to import all the tools required 20 | package tools 21 | 22 | import ( 23 | _ "github.com/golang/mock/mockgen" 24 | _ "k8s.io/code-generator" 25 | _ "sigs.k8s.io/controller-tools/cmd/controller-gen" 26 | ) 27 | -------------------------------------------------------------------------------- /internal/commands/version/version.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package version 18 | 19 | import ( 20 | "fmt" 21 | 22 | "github.com/spf13/cobra" 23 | "gopkg.in/yaml.v2" 24 | 25 | "github.com/fidelity/kconnect/internal/version" 26 | "github.com/fidelity/kconnect/pkg/utils" 27 | ) 28 | 29 | // Command creates the version cobra command 30 | func Command() *cobra.Command { 31 | versionCmd := &cobra.Command{ 32 | Use: "version", 33 | Short: "Display version & build information", 34 | RunE: func(cmd *cobra.Command, args []string) error { 35 | return doVersion(cmd) 36 | }, 37 | } 38 | utils.FormatCommand(versionCmd) 39 | 40 | return versionCmd 41 | } 42 | 43 | func doVersion(_ *cobra.Command) error { 44 | v := version.Get() 45 | outYaml, err := yaml.Marshal(v) 46 | if err != nil { 47 | return fmt.Errorf("marshalling version information: %w", err) 48 | } 49 | fmt.Println(string(outYaml)) //nolint:forbidigo 50 | 51 | return nil 52 | } 53 | -------------------------------------------------------------------------------- /internal/helpers/common.go: -------------------------------------------------------------------------------- 1 | package helpers 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/fidelity/kconnect/pkg/app" 7 | "github.com/fidelity/kconnect/pkg/config" 8 | "github.com/fidelity/kconnect/pkg/defaults" 9 | "github.com/fidelity/kconnect/pkg/flags" 10 | "github.com/spf13/cobra" 11 | ) 12 | 13 | func GetCommonConfig(cmd *cobra.Command, cfg config.ConfigurationSet) (*app.CommonConfig, error) { 14 | flags.PopulateConfigFromCommand(cmd, cfg) 15 | 16 | configPath := cfg.ValueString(app.ConfigPathConfigItem) 17 | if configPath == "" { 18 | configPath = defaults.ConfigPath() 19 | } 20 | 21 | if err := config.ApplyToConfigSetWithProvider(configPath, cfg, ""); err != nil { 22 | return nil, fmt.Errorf("applying app config: %w", err) 23 | } 24 | params := &app.CommonConfig{} 25 | if err := config.Unmarshall(cfg, params); err != nil { 26 | return nil, fmt.Errorf("unmarshalling config into to params: %w", err) 27 | } 28 | 29 | return params, nil 30 | } 31 | -------------------------------------------------------------------------------- /internal/version/checker.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package version 18 | 19 | import ( 20 | "context" 21 | "fmt" 22 | "time" 23 | 24 | "github.com/google/go-github/github" 25 | ) 26 | 27 | // Release contains details of a kconnect release 28 | type Release struct { 29 | Version *string 30 | Date *time.Time 31 | URL *string 32 | } 33 | 34 | // GetLatestRelease gets the latest release detsils from GitHub 35 | func GetLatestRelease() (*Release, error) { 36 | client := github.NewClient(nil) 37 | 38 | release, _, err := client.Repositories.GetLatestRelease(context.TODO(), "fidelity", "kconnect") 39 | if err != nil { 40 | return nil, fmt.Errorf("getting latest release from GitHub: %w", err) 41 | } 42 | 43 | return &Release{ 44 | Version: release.TagName, 45 | Date: &release.PublishedAt.Time, 46 | URL: release.HTMLURL, 47 | }, nil 48 | } 49 | -------------------------------------------------------------------------------- /internal/version/version.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package version 18 | 19 | import ( 20 | "fmt" 21 | "runtime" 22 | ) 23 | 24 | var ( 25 | version string // Specifies the app version 26 | buildDate string // Specifies the build date 27 | commitHash string // Specifies the git commit hash 28 | ) 29 | 30 | // Info represents the version information for the app 31 | type Info struct { 32 | Version string `json:"version,omitempty"` 33 | BuildDate string `json:"buildDate,omitempty"` 34 | CommitHash string `json:"commitHash,omitempty"` 35 | GoVersion string `json:"goVersion,omitempty"` 36 | Platform string `json:"platform,omitempty"` 37 | Compiler string `json:"compiler,omitempty"` 38 | } 39 | 40 | // String will convert the version information to a string 41 | func (i Info) String() string { 42 | return fmt.Sprintf("Version: %s, Build Date: %s, Git Hash: %s", i.Version, i.BuildDate, i.CommitHash) 43 | } 44 | 45 | // Get returns the version information 46 | func Get() Info { 47 | return Info{ 48 | Version: version, 49 | BuildDate: buildDate, 50 | CommitHash: commitHash, 51 | GoVersion: runtime.Version(), 52 | Platform: fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH), 53 | Compiler: runtime.Compiler, 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /pkg/app/errors.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package app 18 | 19 | import "errors" 20 | 21 | var ( 22 | ErrUnknownConfigItemType = errors.New("unknown item type") 23 | ErrClusterNotFound = errors.New("cluster not found") 24 | ErrAliasAlreadyUsed = errors.New("alias already in use") 25 | ErrSourceLocationRequired = errors.New("source location is required for importing") 26 | ErrHistoryLocationRequired = errors.New("history location is required") 27 | ErrHistoryIDRequired = errors.New("history id is required") 28 | ErrAliasRequired = errors.New("alias is required") 29 | ErrAliasAndIDNotAllowed = errors.New("alias and id bith specified, only 1 is allowed") 30 | ErrAliasNotFound = errors.New("no alias found") 31 | ErrNoEntriesFound = errors.New("no entries found") 32 | ErrUnknownProvider = errors.New("unknown provider") 33 | ErrDiscoveryProviderRequired = errors.New("discovery provider required") 34 | ErrIdentityProviderRequired = errors.New("identity provider required") 35 | ErrUnsuportedIdpProtocol = errors.New("unsupported idp protocol") 36 | ) 37 | -------------------------------------------------------------------------------- /pkg/app/list.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package app 18 | 19 | import ( 20 | "context" 21 | "fmt" 22 | "os" 23 | 24 | "go.uber.org/zap" 25 | 26 | "github.com/fidelity/kconnect/api/v1alpha1" 27 | "github.com/fidelity/kconnect/pkg/history" 28 | "github.com/fidelity/kconnect/pkg/k8s/kubeconfig" 29 | "github.com/fidelity/kconnect/pkg/printer" 30 | ) 31 | 32 | type HistoryQueryInput struct { 33 | HistoryConfig 34 | KubernetesConfig 35 | HistoryQueryConfig 36 | 37 | ClusterProvider *string `json:"cluster-provider,omitempty"` 38 | IdentityProvider *string `json:"identity-provider,omitempty"` 39 | 40 | ProviderID *string `json:"provider-id,omitempty"` 41 | HistoryID *string `json:"id,omitempty"` 42 | Alias *string `json:"alias,omitempty"` 43 | 44 | Flags map[string]string `json:"flags,omitempty"` 45 | 46 | Output *printer.OutputPrinter `json:"output,omitempty"` 47 | } 48 | 49 | func (a *App) QueryHistory(ctx context.Context, input *HistoryQueryInput) error { 50 | zap.S().Debug("querying history") 51 | 52 | list, err := a.historyStore.GetAllSortedByLastUsed() 53 | if err != nil { 54 | return fmt.Errorf("getting history entries: %w", err) 55 | } 56 | 57 | filterSpec := createFilter(input.Filter) 58 | 59 | if err := history.FilterHistory(list, filterSpec); err != nil { 60 | return fmt.Errorf("filtering history list: %w", err) 61 | } 62 | 63 | objPrinter, err := printer.New(*input.Output) 64 | if err != nil { 65 | return fmt.Errorf("getting printer for output %s: %w", *input.Output, err) 66 | } 67 | 68 | if *input.Output == printer.OutputPrinterTable { 69 | 70 | currentContexID, err := a.getCurrentContextID(input.Kubeconfig) 71 | if err != nil { 72 | zap.S().Warnf("Error getting current context ID: %s", err) 73 | } 74 | return objPrinter.Print(list.ToTable(currentContexID), os.Stdout) 75 | } 76 | 77 | return objPrinter.Print(list, os.Stdout) 78 | } 79 | 80 | func (a *App) getCurrentContextID(kubecfg string) (string, error) { 81 | currentContext, err := kubeconfig.GetCurrentContext(kubecfg) 82 | if err != nil { 83 | return "", err 84 | } 85 | if currentContext == nil || currentContext.Extensions == nil { 86 | return "", nil 87 | } 88 | currentContextHistoryReference, err := v1alpha1.GetHistoryReferenceFromContext(currentContext) 89 | if err != nil { 90 | return "", err 91 | } 92 | currentContexID := currentContextHistoryReference.EntryID 93 | return currentContexID, nil 94 | } 95 | -------------------------------------------------------------------------------- /pkg/aws/awsconfig/awsconfig.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package awsconfig 18 | 19 | import ( 20 | "os" 21 | "path" 22 | "path/filepath" 23 | "runtime" 24 | 25 | "github.com/mitchellh/go-homedir" 26 | "github.com/pkg/errors" 27 | ) 28 | 29 | // Taken from saml2aws 30 | func LocateConfigFile() (string, error) { 31 | 32 | filename := os.Getenv("AWS_SHARED_CREDENTIALS_FILE") 33 | 34 | if filename != "" { 35 | return filename, nil 36 | } 37 | 38 | var name string 39 | var err error 40 | if runtime.GOOS == "windows" { 41 | name = path.Join(os.Getenv("USERPROFILE"), ".aws", "credentials") 42 | } else { 43 | name, err = homedir.Expand("~/.aws/credentials") 44 | if err != nil { 45 | return "", err 46 | } 47 | } 48 | 49 | // is the filename a symlink? 50 | name, err = resolveSymlink(name) 51 | if err != nil { 52 | return "", errors.Wrap(err, "unable to resolve symlink") 53 | } 54 | return name, nil 55 | } 56 | 57 | func resolveSymlink(filename string) (string, error) { 58 | sympath, err := filepath.EvalSymlinks(filename) 59 | 60 | // return the un modified filename 61 | if os.IsNotExist(err) { 62 | return filename, nil 63 | } 64 | if err != nil { 65 | return "", err 66 | } 67 | 68 | return sympath, nil 69 | } 70 | -------------------------------------------------------------------------------- /pkg/aws/clients.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package aws 18 | 19 | import ( 20 | "fmt" 21 | 22 | "github.com/aws/aws-sdk-go/aws" 23 | "github.com/aws/aws-sdk-go/aws/client" 24 | "github.com/aws/aws-sdk-go/aws/credentials" 25 | "github.com/aws/aws-sdk-go/aws/request" 26 | "github.com/aws/aws-sdk-go/aws/session" 27 | "github.com/aws/aws-sdk-go/service/eks" 28 | "github.com/aws/aws-sdk-go/service/eks/eksiface" 29 | "github.com/aws/aws-sdk-go/service/iam" 30 | "github.com/aws/aws-sdk-go/service/iam/iamiface" 31 | 32 | "github.com/fidelity/kconnect/internal/version" 33 | ) 34 | 35 | func NewSession(region, profile, accessKey, secretKey, sessionToken, awsSharedCredentialsFile string) (*session.Session, error) { 36 | cfg := aws.Config{ 37 | Region: aws.String(region), 38 | } 39 | 40 | if profile != "" { 41 | cfg.Credentials = credentials.NewSharedCredentials(awsSharedCredentialsFile, profile) 42 | } else if accessKey != "" && secretKey != "" { 43 | cfg.Credentials = credentials.NewStaticCredentials(accessKey, secretKey, sessionToken) 44 | } 45 | 46 | options := session.Options{ 47 | SharedConfigState: session.SharedConfigEnable, 48 | Config: cfg, 49 | } 50 | 51 | awsSession, err := session.NewSessionWithOptions(options) 52 | if err != nil { 53 | return nil, fmt.Errorf("creating new aws session in region %s using creds: %w", region, err) 54 | } 55 | 56 | return awsSession, nil 57 | } 58 | 59 | func NewIAMClient(session client.ConfigProvider) iamiface.IAMAPI { 60 | iamClient := iam.New(session) 61 | iamClient.Handlers.Build.PushFrontNamed(getUserAgentHandler()) 62 | 63 | return iamClient 64 | } 65 | 66 | func NewEKSClient(session client.ConfigProvider) eksiface.EKSAPI { 67 | eksClient := eks.New(session) 68 | eksClient.Handlers.Build.PushFrontNamed(getUserAgentHandler()) 69 | 70 | return eksClient 71 | } 72 | 73 | func getUserAgentHandler() request.NamedHandler { 74 | return request.NamedHandler{ 75 | Name: "kconnect/user-agent", 76 | Fn: request.MakeAddToUserAgentHandler("kconnect.fidelity.github.com", version.Get().String()), 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /pkg/aws/config.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package aws 18 | 19 | import ( 20 | "github.com/aws/aws-sdk-go/aws/endpoints" 21 | "github.com/fidelity/kconnect/pkg/config" 22 | ) 23 | 24 | const ( 25 | RegionConfigItem = "region" 26 | PartitionConfigItem = "partition" 27 | ProfileConfigItem = "profile" 28 | AccessKeyConfigItem = "access-key" 29 | SecretKeyConfigItem = "secret-key" 30 | SessionTokenConfigItem = "session-token" 31 | ) 32 | 33 | // SharedConfig will return shared configuration items for AWS based cluster and identity providers 34 | func SharedConfig() config.ConfigurationSet { 35 | cs := config.NewConfigurationSet() 36 | AddPartitionConfig(cs) 37 | AddRegionConfig(cs) 38 | cs.String("static-profile", "", "AWS profile to use. Only for advanced use cases") //nolint: errcheck 39 | cs.SetHidden("static-profile") //nolint: errcheck 40 | 41 | return cs 42 | } 43 | 44 | func AddRegionConfig(cs config.ConfigurationSet) { 45 | cs.String(RegionConfigItem, "", "AWS region to connect to") //nolint: errcheck 46 | cs.SetRequired(RegionConfigItem) //nolint: errcheck 47 | } 48 | 49 | func AddPartitionConfig(cs config.ConfigurationSet) { 50 | cs.String(PartitionConfigItem, endpoints.AwsPartition().ID(), "AWS partition to use") //nolint: errcheck 51 | cs.SetRequired(ProfileConfigItem) //nolint: errcheck 52 | } 53 | 54 | func AddIAMConfigs(cs config.ConfigurationSet) { 55 | cs.String(ProfileConfigItem, "", "AWS profile to use") //nolint: errcheck 56 | cs.String(AccessKeyConfigItem, "", "AWS access key to use") //nolint: errcheck 57 | cs.String(SecretKeyConfigItem, "", "AWS secret key to use") //nolint: errcheck 58 | cs.String(SessionTokenConfigItem, "", "AWS session token to use") //nolint: errcheck 59 | } 60 | -------------------------------------------------------------------------------- /pkg/aws/errors.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package aws 18 | 19 | import "errors" 20 | 21 | var ( 22 | ErrNoProfile = errors.New("no profile supplied") 23 | ErrUnexpectedIdentity = errors.New("unexpected identity type") 24 | ErrNoPartitionSupplied = errors.New("no AWS partition supplied") 25 | ErrPartitionNotFound = errors.New("AWS partition not found") 26 | ) 27 | -------------------------------------------------------------------------------- /pkg/aws/identifer.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package aws 18 | 19 | import ( 20 | "errors" 21 | "fmt" 22 | "hash/fnv" 23 | 24 | "github.com/versent/saml2aws/v2/pkg/awsconfig" 25 | ) 26 | 27 | var ( 28 | ErrPrincipleARNRequired = errors.New("principle arn is required ") 29 | ) 30 | 31 | // CreateIDFromCreds will create a unique identifier for a set of credentials. The identifier 32 | // is a hash of the principle ARN 33 | func CreateIDFromCreds(creds *awsconfig.AWSCredentials) (string, error) { 34 | if creds.PrincipalARN == "" { 35 | return "", ErrPrincipleARNRequired 36 | } 37 | h := fnv.New32a() 38 | if _, err := h.Write([]byte(creds.PrincipalARN)); err != nil { 39 | return "", fmt.Errorf("write to has function: %w", err) 40 | } 41 | 42 | return fmt.Sprintf("%d", h.Sum32()), nil 43 | } 44 | -------------------------------------------------------------------------------- /pkg/aws/identity.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package aws 18 | 19 | import ( 20 | "time" 21 | ) 22 | 23 | // Identity represents an AWS identity 24 | type Identity struct { 25 | ProfileName string 26 | AWSAccessKey string 27 | AWSSecretKey string 28 | AWSSessionToken string 29 | AWSSecurityToken string 30 | PrincipalARN string 31 | Expires time.Time 32 | Region string 33 | AWSSharedCredentialsFile string 34 | IDProviderName string 35 | } 36 | 37 | func (i *Identity) Type() string { 38 | return "aws" 39 | } 40 | 41 | func (i *Identity) Name() string { 42 | return i.PrincipalARN 43 | } 44 | 45 | func (i *Identity) IsExpired() bool { 46 | now := time.Now().UTC() 47 | return now.After(i.Expires) 48 | } 49 | 50 | func (i *Identity) IdentityProviderName() string { 51 | return i.IDProviderName 52 | } 53 | -------------------------------------------------------------------------------- /pkg/aws/map.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package aws 18 | 19 | import "github.com/versent/saml2aws/v2/pkg/awsconfig" 20 | 21 | func MapCredsToIdentity(creds *awsconfig.AWSCredentials, profileName, awsSharedCredentialsFile string) *Identity { 22 | return &Identity{ 23 | AWSAccessKey: creds.AWSAccessKey, 24 | AWSSecretKey: creds.AWSSecretKey, 25 | AWSSecurityToken: creds.AWSSecurityToken, 26 | AWSSessionToken: creds.AWSSessionToken, 27 | AWSSharedCredentialsFile: awsSharedCredentialsFile, 28 | Expires: creds.Expires, 29 | PrincipalARN: creds.PrincipalARN, 30 | ProfileName: profileName, 31 | Region: creds.Region, 32 | } 33 | } 34 | 35 | func MapIdentityToCreds(awsIdentity *Identity) *awsconfig.AWSCredentials { 36 | return &awsconfig.AWSCredentials{ 37 | AWSAccessKey: awsIdentity.AWSAccessKey, 38 | AWSSecretKey: awsIdentity.AWSSecretKey, 39 | AWSSecurityToken: awsIdentity.AWSSecurityToken, 40 | AWSSessionToken: awsIdentity.AWSSessionToken, 41 | Expires: awsIdentity.Expires, 42 | PrincipalARN: awsIdentity.PrincipalARN, 43 | Region: awsIdentity.Region, 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /pkg/aws/resolve.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package aws 18 | 19 | import ( 20 | "fmt" 21 | "sort" 22 | 23 | "github.com/aws/aws-sdk-go/aws/endpoints" 24 | 25 | "github.com/fidelity/kconnect/pkg/config" 26 | "github.com/fidelity/kconnect/pkg/prompt" 27 | "github.com/fidelity/kconnect/pkg/utils" 28 | ) 29 | 30 | func ResolvePartition(cfg config.ConfigurationSet) error { 31 | return prompt.ChooseAndSet(cfg, PartitionConfigItem, "Select the AWS partition", true, awsPartitionOptions) 32 | } 33 | 34 | func ResolveRegion(cfg config.ConfigurationSet) error { 35 | if cfg.ExistsWithValue(RegionConfigItem) { 36 | return nil 37 | } 38 | 39 | partitionCfg := cfg.Get("partition") 40 | if partitionCfg == nil { 41 | return ErrNoPartitionSupplied 42 | } 43 | partitionID := partitionCfg.Value.(string) 44 | 45 | resolver := endpoints.DefaultResolver() 46 | partitions := resolver.(endpoints.EnumPartitions).Partitions() 47 | 48 | var partition endpoints.Partition 49 | for _, p := range partitions { 50 | if p.ID() == partitionID { 51 | partition = p 52 | break 53 | } 54 | } 55 | if partition.ID() == "" { 56 | return fmt.Errorf("finding partition with id %s: %w", partitionID, ErrPartitionNotFound) 57 | } 58 | 59 | regionFilter := "" 60 | regionFilterCfg := cfg.Get("region-filter") 61 | if regionFilterCfg != nil { 62 | regionFilter = regionFilterCfg.Value.(string) 63 | } 64 | 65 | options := []string{} 66 | for _, region := range partition.Regions() { 67 | options = append(options, region.ID()) 68 | } 69 | options, err := utils.RegexFilter(options, regionFilter) 70 | if err != nil { 71 | return fmt.Errorf("applying region regex %s : %w", regionFilter, err) 72 | } 73 | 74 | sort.Slice(options, func(i, j int) bool { return options[i] < options[j] }) 75 | 76 | err = prompt.ChooseAndSet(cfg, RegionConfigItem, "Select an AWS region", true, prompt.OptionsFromStringSlice(options)) 77 | if err != nil { 78 | return fmt.Errorf("choosing and setting %s: %w", RegionConfigItem, err) 79 | } 80 | 81 | return nil 82 | } 83 | 84 | func awsPartitionOptions() (map[string]string, error) { 85 | resolver := endpoints.DefaultResolver() 86 | partitions := resolver.(endpoints.EnumPartitions).Partitions() 87 | 88 | options := map[string]string{} 89 | for _, partition := range partitions { 90 | options[partition.ID()] = partition.ID() 91 | } 92 | 93 | return options, nil 94 | } 95 | -------------------------------------------------------------------------------- /pkg/aws/store.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package aws 18 | 19 | import ( 20 | "fmt" 21 | 22 | "github.com/versent/saml2aws/v2/pkg/awsconfig" 23 | 24 | kawsconfig "github.com/fidelity/kconnect/pkg/aws/awsconfig" 25 | "github.com/fidelity/kconnect/pkg/provider/identity" 26 | ) 27 | 28 | // NewIdentityStore will create a new AWS identity store 29 | func NewIdentityStore(profile, idProviderName, awsCredsFile string) (identity.Store, error) { 30 | path, _ := kawsconfig.LocateConfigFile() 31 | configProvider := awsconfig.NewSharedCredentials(profile, path) 32 | if awsCredsFile != "" { 33 | configProvider.Filename = awsCredsFile 34 | } 35 | return &awsIdentityStore{ 36 | configProvider: configProvider, 37 | idProviderName: idProviderName, 38 | }, nil 39 | } 40 | 41 | type awsIdentityStore struct { 42 | configProvider *awsconfig.CredentialsProvider 43 | idProviderName string 44 | } 45 | 46 | func (s *awsIdentityStore) CredsExists() (bool, error) { 47 | return s.configProvider.CredsExists() 48 | } 49 | 50 | func (s *awsIdentityStore) Save(userID identity.Identity) error { 51 | awsIdentity, ok := userID.(*Identity) 52 | if !ok { 53 | return fmt.Errorf("expected AWSIdentity but got a %T: %w", userID, ErrUnexpectedIdentity) 54 | } 55 | awsCreds := MapIdentityToCreds(awsIdentity) 56 | 57 | return s.configProvider.Save(awsCreds) 58 | } 59 | 60 | func (s *awsIdentityStore) Load() (identity.Identity, error) { 61 | creds, err := s.configProvider.Load() 62 | if err != nil { 63 | return nil, fmt.Errorf("loading credentials: %w", err) 64 | } 65 | awsID := MapCredsToIdentity(creds, s.configProvider.Profile, s.configProvider.Filename) 66 | 67 | return awsID, nil 68 | } 69 | 70 | func (s *awsIdentityStore) Expired() bool { 71 | return s.configProvider.Expired() 72 | } 73 | -------------------------------------------------------------------------------- /pkg/azure/client/client.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package client 18 | 19 | import ( 20 | "fmt" 21 | 22 | "github.com/Azure/azure-sdk-for-go/services/containerservice/mgmt/2022-03-01/containerservice" 23 | "github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2019-11-01/subscriptions" 24 | "github.com/Azure/go-autorest/autorest" 25 | 26 | "github.com/fidelity/kconnect/internal/version" 27 | ) 28 | 29 | const ( 30 | userAgentTemplate = "kconnect.fidelity.github.com/%s" 31 | ) 32 | 33 | // NewContainerClient will create a new Azure container services client 34 | func NewContainerClient(subscriptionID string, authorizer autorest.Authorizer) containerservice.ManagedClustersClient { 35 | azclient := containerservice.NewManagedClustersClient(subscriptionID) 36 | azclient.Authorizer = authorizer 37 | azclient.UserAgent = fmt.Sprintf(userAgentTemplate, version.Get().String()) 38 | 39 | return azclient 40 | } 41 | 42 | // NewSubscriptionsClient will create a new Azure subscriptions client 43 | func NewSubscriptionsClient(authorizer autorest.Authorizer) subscriptions.Client { 44 | subClient := subscriptions.NewClient() 45 | subClient.Authorizer = authorizer 46 | subClient.UserAgent = fmt.Sprintf(userAgentTemplate, version.Get().String()) 47 | 48 | return subClient 49 | } 50 | -------------------------------------------------------------------------------- /pkg/azure/id/cluster.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package id 18 | 19 | import ( 20 | "errors" 21 | "fmt" 22 | "strings" 23 | ) 24 | 25 | const ( 26 | ContainerServiceProvider = "Microsoft.ContainerService" 27 | ManagedClustersResource = "managedClusters" 28 | 29 | clusterIDPartsNum = 3 30 | resourceIDPartsNum = 8 31 | ) 32 | 33 | var ( 34 | ErrNotContainerService = errors.New("cluster is not for the container service") 35 | ErrNotManagedCluster = errors.New("resource type is not a managed cluster") 36 | ErrUnrecognizedClusterID = errors.New("cluster id in unrecognized format") 37 | ) 38 | 39 | // ToClusterID creates a cluster id based on an azure resource id 40 | func ToClusterID(clusterResourceID string) (string, error) { 41 | resourceID, err := Parse(clusterResourceID) 42 | if err != nil { 43 | return "", fmt.Errorf("parsing cluster id: %w", err) 44 | } 45 | 46 | if resourceID.Provider != ContainerServiceProvider { 47 | return "", ErrNotContainerService 48 | } 49 | if resourceID.ResourceType != ManagedClustersResource { 50 | return "", ErrNotManagedCluster 51 | } 52 | 53 | generatedID := fmt.Sprintf("%s/%s/%s", resourceID.SubscriptionID, resourceID.ResourceGroupName, resourceID.ResourceName) 54 | 55 | return generatedID, nil 56 | } 57 | 58 | // FromClusterID will create a ResourceIdentifer from a cluster id 59 | func FromClusterID(clusterID string) (*ResourceIdentifier, error) { 60 | parts := strings.Split(clusterID, "/") 61 | if len(parts) != clusterIDPartsNum { 62 | return nil, ErrUnrecognizedClusterID 63 | } 64 | 65 | return &ResourceIdentifier{ 66 | Provider: ContainerServiceProvider, 67 | ResourceType: ManagedClustersResource, 68 | SubscriptionID: parts[0], 69 | ResourceGroupName: parts[1], 70 | ResourceName: parts[2], 71 | }, nil 72 | } 73 | -------------------------------------------------------------------------------- /pkg/azure/id/cluster_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package id_test 18 | 19 | import ( 20 | "testing" 21 | 22 | "github.com/brianvoe/gofakeit/v5" 23 | . "github.com/onsi/gomega" 24 | 25 | "github.com/fidelity/kconnect/pkg/azure/id" 26 | ) 27 | 28 | func TestClusterResourceConvFuzz(t *testing.T) { 29 | g := NewWithT(t) 30 | 31 | for i := 0; i < 100; i++ { 32 | original := &id.ResourceIdentifier{ 33 | Provider: id.ContainerServiceProvider, 34 | ResourceType: id.ManagedClustersResource, 35 | SubscriptionID: gofakeit.UUID(), 36 | ResourceGroupName: gofakeit.Word(), 37 | ResourceName: gofakeit.Word(), 38 | } 39 | 40 | clusterID, err := id.ToClusterID(original.String()) 41 | g.Expect(err).ToNot(HaveOccurred()) 42 | 43 | final, err := id.FromClusterID(clusterID) 44 | 45 | g.Expect(err).ToNot(HaveOccurred()) 46 | g.Expect(final).To(BeEquivalentTo(original)) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /pkg/azure/id/resource.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package id 18 | 19 | import ( 20 | "errors" 21 | "fmt" 22 | "strings" 23 | ) 24 | 25 | var ( 26 | // ErrIDUnrecognizedFormat is an error if the format of the resource id is unrecognozed 27 | ErrIDUnrecognizedFormat = errors.New("resource id format is unrecognized") 28 | ) 29 | 30 | // ResourceIdentifier represents the uniqie identifier for a resource 31 | type ResourceIdentifier struct { 32 | SubscriptionID string 33 | ResourceGroupName string 34 | Provider string 35 | ResourceType string 36 | ResourceName string 37 | } 38 | 39 | // String retruns the string representation of the resource identifier 40 | func (r *ResourceIdentifier) String() string { 41 | return fmt.Sprintf("/subscriptions/%s/resourcegroups/%s/providers/%s/%s/%s", 42 | r.SubscriptionID, 43 | r.ResourceGroupName, 44 | r.Provider, 45 | r.ResourceType, 46 | r.ResourceName, 47 | ) 48 | } 49 | 50 | // Parse will create a AzureIdentifier from a id string 51 | func Parse(resourceID string) (*ResourceIdentifier, error) { 52 | resourceID = strings.TrimPrefix(resourceID, "/") 53 | 54 | parts := strings.Split(resourceID, "/") 55 | if len(parts) != resourceIDPartsNum { 56 | return nil, ErrIDUnrecognizedFormat 57 | } 58 | 59 | if parts[0] != "subscriptions" { 60 | return nil, fmt.Errorf("finding subscription: %w", ErrIDUnrecognizedFormat) 61 | } 62 | subscriptionID := parts[1] 63 | 64 | if parts[2] != "resourcegroups" { 65 | return nil, fmt.Errorf("finding resource group: %w", ErrIDUnrecognizedFormat) 66 | } 67 | resourceGroupName := parts[3] 68 | 69 | if parts[4] != "providers" { 70 | return nil, fmt.Errorf("finding provider: %w", ErrIDUnrecognizedFormat) 71 | } 72 | providerName := parts[5] 73 | 74 | azureIdentifier := &ResourceIdentifier{ 75 | SubscriptionID: subscriptionID, 76 | ResourceGroupName: resourceGroupName, 77 | Provider: providerName, 78 | ResourceType: parts[6], 79 | ResourceName: parts[7], 80 | } 81 | 82 | return azureIdentifier, nil 83 | } 84 | -------------------------------------------------------------------------------- /pkg/azure/id/resource_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package id_test 18 | 19 | import ( 20 | "testing" 21 | 22 | . "github.com/onsi/gomega" 23 | 24 | "github.com/fidelity/kconnect/pkg/azure/id" 25 | ) 26 | 27 | func TestResourceParse(t *testing.T) { 28 | testCases := []struct { 29 | name string 30 | idInput string 31 | expectErr bool 32 | expectedId *id.ResourceIdentifier 33 | }{ 34 | { 35 | name: "container service parse", 36 | idInput: "/subscriptions/6c667d97-8ee0-40d5-a233-03b3f890b690/resourcegroups/rg-test-1/providers/Microsoft.ContainerService/managedClusters/my-test-cluster", 37 | expectErr: false, 38 | expectedId: &id.ResourceIdentifier{ 39 | Provider: "Microsoft.ContainerService", 40 | ResourceGroupName: "rg-test-1", 41 | ResourceName: "my-test-cluster", 42 | ResourceType: "managedClusters", 43 | SubscriptionID: "6c667d97-8ee0-40d5-a233-03b3f890b690", 44 | }, 45 | }, 46 | { 47 | name: "no subscriptions", 48 | idInput: "/6c667d97-8ee0-40d5-a233-03b3f890b690/resourcegroups/rg-test-1/providers/Microsoft.ContainerService/managedClusters/my-test-cluster", 49 | expectErr: true, 50 | }, 51 | } 52 | 53 | for _, tc := range testCases { 54 | t.Run(tc.name, func(t *testing.T) { 55 | g := NewWithT(t) 56 | 57 | actualID, err := id.Parse(tc.idInput) 58 | if tc.expectErr { 59 | g.Expect(err).To(HaveOccurred()) 60 | } else { 61 | g.Expect(err).ToNot(HaveOccurred()) 62 | g.Expect(actualID).To(BeEquivalentTo(tc.expectedId)) 63 | } 64 | }) 65 | } 66 | } 67 | 68 | func TestResourceString(t *testing.T) { 69 | g := NewWithT(t) 70 | 71 | expectedID := "/subscriptions/6c667d97-8ee0-40d5-a233-03b3f890b690/resourcegroups/rg-test-1/providers/Microsoft.ContainerService/managedClusters/my-test-cluster" 72 | 73 | resourceID := &id.ResourceIdentifier{ 74 | Provider: "Microsoft.ContainerService", 75 | ResourceGroupName: "rg-test-1", 76 | ResourceName: "my-test-cluster", 77 | ResourceType: "managedClusters", 78 | SubscriptionID: "6c667d97-8ee0-40d5-a233-03b3f890b690", 79 | } 80 | 81 | actualID := resourceID.String() 82 | 83 | g.Expect(actualID).To(Equal(expectedID)) 84 | 85 | } 86 | -------------------------------------------------------------------------------- /pkg/azure/identity/authorizer.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package identity 18 | 19 | import ( 20 | "fmt" 21 | "net/http" 22 | 23 | "github.com/Azure/go-autorest/autorest" 24 | ) 25 | 26 | // ExplicitBearerAuthorizer implements a bearer token authorizer where the token is supplied at 27 | // creation and not via a token provider 28 | type ExplicitBearerAuthorizer struct { 29 | token string 30 | } 31 | 32 | // NewExplicitBearerAuthorizer creates a new ExplicitBearerAuthorizer with the specified token. 33 | func NewExplicitBearerAuthorizer(token string) *ExplicitBearerAuthorizer { 34 | return &ExplicitBearerAuthorizer{ 35 | token: token, 36 | } 37 | } 38 | 39 | // WithAuthorization returns a PrepareDecorator that adds an HTTP Authorization header whose 40 | // value is "Bearer " followed by the bearer token 41 | func (ba *ExplicitBearerAuthorizer) WithAuthorization() autorest.PrepareDecorator { 42 | return func(p autorest.Preparer) autorest.Preparer { 43 | return autorest.PreparerFunc(func(r *http.Request) (*http.Request, error) { 44 | r, err := p.Prepare(r) 45 | if err == nil { 46 | return autorest.Prepare(r, autorest.WithHeader("Authorization", fmt.Sprintf("Bearer %s", ba.token))) 47 | } 48 | return r, err 49 | }) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /pkg/azure/identity/errors.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package identity 18 | 19 | import "errors" 20 | 21 | var ( 22 | ErrInvalidResponseCode = errors.New("invalid response code") 23 | ErrAuthorizationEndpointNotFound = errors.New("authorize endpoint wasn't found") 24 | ErrTokenEndpointNotFound = errors.New("token endpoint not found") 25 | ErrIssuerNotFound = errors.New("issues not found") 26 | ErrUnknownAccountType = errors.New("unknown account type") 27 | ErrOIDCResponse = errors.New("oidc error") 28 | ErrResourceRequired = errors.New("you must supply a resource") 29 | ) 30 | -------------------------------------------------------------------------------- /pkg/azure/wstrust/saml_token_info.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT license. 3 | 4 | package wstrust 5 | 6 | type SamlAssertionType int 7 | 8 | const ( 9 | SamlV1 SamlAssertionType = iota 10 | SamlV2 11 | ) 12 | 13 | type SamlTokenInfo struct { 14 | AssertionType SamlAssertionType 15 | Assertion string 16 | } 17 | 18 | func createSamlTokenInfo(assertionType SamlAssertionType, assertion string) *SamlTokenInfo { 19 | tokenInfo := &SamlTokenInfo{assertionType, assertion} 20 | return tokenInfo 21 | } 22 | -------------------------------------------------------------------------------- /pkg/azure/wstrust/wstrust_response.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT license. 3 | 4 | package wstrust 5 | 6 | import ( 7 | "encoding/xml" 8 | "errors" 9 | "fmt" 10 | 11 | log "github.com/sirupsen/logrus" 12 | ) 13 | 14 | type Response struct { 15 | responseData string 16 | } 17 | 18 | func CreateWsTrustResponse(responseData string) *Response { 19 | response := &Response{responseData} 20 | return response 21 | 22 | // todo: return error here 23 | // pugi::xml_parse_result result = _doc.load_string(response.c_str()); 24 | // if (!result) 25 | // { 26 | // "Failed to parse SAML response '%s', response"); 27 | // } 28 | 29 | // auto fault = _doc.child("s:Envelope").child("s:Body").child("s:Fault"); 30 | // if (fault != nullptr) 31 | // { 32 | // "SAML assertion indicates error: Code '%s' Subcode '%s' Reason '%s'", 33 | // fault.child("s:Code").child_value("s:Value"), 34 | // fault.child("s:Code").child("s:Subcode").child_value("s:Value"), 35 | // fault.child("s:Reason").child_value("s:Text")); 36 | // } 37 | } 38 | 39 | func (wsTrustResponse *Response) GetSAMLAssertion(endpoint *Endpoint) (*SamlTokenInfo, error) { 40 | switch endpoint.EndpointVersion { 41 | case Trust2005: 42 | return nil, errors.New("WS Trust 2005 support is not implemented") 43 | case Trust13: 44 | { 45 | log.Trace("Extracting assertion from WS-Trust 1.3 token:") 46 | 47 | samldefinitions := &samldefinitions{} 48 | var err = xml.Unmarshal([]byte(wsTrustResponse.responseData), samldefinitions) 49 | if err != nil { 50 | return nil, err 51 | } 52 | 53 | for _, tokenResponse := range samldefinitions.Body.RequestSecurityTokenResponseCollection.RequestSecurityTokenResponse { 54 | token := tokenResponse.RequestedSecurityToken 55 | if token.Assertion.XMLName.Local != "" { 56 | log.Trace("Found valid assertion") 57 | assertion := token.AssertionRawXML 58 | 59 | samlVersion := token.Assertion.Saml 60 | if samlVersion == "urn:oasis:names:tc:SAML:1.0:assertion" { 61 | log.Trace("Retrieved WS-Trust 1.3 / SAML V1 assertion") 62 | return createSamlTokenInfo(SamlV1, assertion), nil 63 | } 64 | if samlVersion == "urn:oasis:names:tc:SAML:2.0:assertion" { 65 | log.Trace("Retrieved WS-Trust 1.3 / SAML V2 assertion") 66 | return createSamlTokenInfo(SamlV2, assertion), nil 67 | } 68 | 69 | return nil, fmt.Errorf("Couldn't parse SAML assertion, version unknown: '%s'", samlVersion) 70 | } 71 | } 72 | 73 | return nil, errors.New("couldn't find SAML assertion") 74 | } 75 | default: 76 | return nil, errors.New("unknown WS-Trust version") 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /pkg/config/apply.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package config 18 | 19 | import ( 20 | "fmt" 21 | "strconv" 22 | ) 23 | 24 | // ApplyToConfigSet will apply the saved app configuration to the supplied config set. 25 | func ApplyToConfigSet(configPath string, cs ConfigurationSet) error { 26 | return applyConfiguration(configPath, cs, "") 27 | } 28 | 29 | // ApplyToConfigSetWithProvider will apply the saved app configuration to the supplied config set and 30 | // will take into consideration provider specific overrides 31 | func ApplyToConfigSetWithProvider(configPath string, cs ConfigurationSet, provider string) error { 32 | return applyConfiguration(configPath, cs, provider) 33 | } 34 | 35 | func applyConfiguration(configPath string, cs ConfigurationSet, provider string) error { 36 | appConfig, err := NewAppConfigurationWithPath(configPath) 37 | if err != nil { 38 | return fmt.Errorf("creating app config store: %w", err) 39 | } 40 | 41 | cfg, err := appConfig.Get() 42 | if err != nil { 43 | return fmt.Errorf("getting app config: %w", err) 44 | } 45 | 46 | for _, item := range cs.GetAll() { 47 | if item.HasValue() { 48 | continue 49 | } 50 | 51 | // apply provider specific value first 52 | providerValues, hasProvider := cfg.Spec.Providers[provider] 53 | if hasProvider { 54 | providerVal, hasProviderVal := providerValues[item.Name] 55 | if hasProviderVal { 56 | if err := setItemValue(item, providerVal); err != nil { 57 | return fmt.Errorf("setting item value for %s from provider config: %w", item.Name, err) 58 | } 59 | continue 60 | } 61 | } 62 | 63 | // apply global value if we have one 64 | globalVal, hasGlobalVal := cfg.Spec.Global[item.Name] 65 | if hasGlobalVal { 66 | if err := setItemValue(item, globalVal); err != nil { 67 | return fmt.Errorf("setting item value for %s from global config: %w", item.Name, err) 68 | } 69 | continue 70 | } 71 | } 72 | 73 | return nil 74 | } 75 | 76 | func setItemValue(item *Item, value string) error { 77 | switch item.Type { 78 | case ItemTypeString: 79 | item.Value = value 80 | return nil 81 | case ItemTypeInt: 82 | intVal, err := strconv.ParseInt(value, 10, 32) 83 | if err != nil { 84 | return fmt.Errorf("parsing config as int: %w", err) 85 | } 86 | item.Value = intVal 87 | return nil 88 | case ItemTypeBool: 89 | boolVal, err := strconv.ParseBool(value) 90 | if err != nil { 91 | return fmt.Errorf("parsing config as bool: %w", err) 92 | } 93 | item.Value = boolVal 94 | return nil 95 | default: 96 | return ErrUnknownItemType 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /pkg/config/errors.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package config 18 | 19 | import "errors" 20 | 21 | var ( 22 | ErrListNotFound = errors.New("list not found") 23 | ) 24 | -------------------------------------------------------------------------------- /pkg/config/unmarshall.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package config 18 | 19 | import ( 20 | "encoding/json" 21 | ) 22 | 23 | // Unmarshall will unmarshall the ConfigurationSet into a struct 24 | func Unmarshall(cs ConfigurationSet, out interface{}) error { 25 | items := make(map[string]interface{}) 26 | for _, item := range cs.GetAll() { 27 | items[item.Name] = item.Value 28 | } 29 | 30 | data, err := json.Marshal(items) 31 | if err != nil { 32 | return err 33 | } 34 | 35 | if err := json.Unmarshal(data, out); err != nil { 36 | return err 37 | } 38 | 39 | return nil 40 | } 41 | -------------------------------------------------------------------------------- /pkg/defaults/defaults.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package defaults 18 | 19 | import ( 20 | "os" 21 | "path" 22 | ) 23 | 24 | const ( 25 | RootFolderName = ".kconnect" 26 | MaxHistoryItems = 100 27 | // DefaultUIPageSize specifies the default number of items to display to a user 28 | DefaultUIPageSize = 10 29 | 30 | UsernameConfigItem = "username" 31 | PasswordConfigItem = "password" 32 | ) 33 | 34 | func AppDirectory() string { 35 | dir, err := os.UserHomeDir() 36 | if err != nil { 37 | return "" 38 | } 39 | 40 | return path.Join(dir, RootFolderName) 41 | } 42 | 43 | func HistoryPath() string { 44 | appDir := AppDirectory() 45 | 46 | return path.Join(appDir, "history.yaml") 47 | } 48 | 49 | func ConfigPath() string { 50 | appDir := AppDirectory() 51 | 52 | return path.Join(appDir, "config.yaml") 53 | } 54 | -------------------------------------------------------------------------------- /pkg/defaults/http.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package defaults 18 | 19 | import ( 20 | "fmt" 21 | 22 | "github.com/fidelity/kconnect/internal/version" 23 | "github.com/fidelity/kconnect/pkg/http" 24 | ) 25 | 26 | type Option func(map[string]string) 27 | 28 | func Headers(opts ...Option) map[string]string { 29 | v := version.Get() 30 | 31 | headers := make(map[string]string) 32 | headers["User-Agent"] = fmt.Sprintf("kconnect/%s", v.Version) 33 | 34 | for _, opt := range opts { 35 | opt(headers) 36 | } 37 | 38 | return headers 39 | } 40 | 41 | func WithNoCache() Option { 42 | return func(headers map[string]string) { 43 | headers["Cache-Control"] = "no-cache" 44 | } 45 | } 46 | 47 | func WithJSON() Option { 48 | return func(headers map[string]string) { 49 | headers["Accept"] = http.MediaTypeJSON 50 | headers["Content-Type"] = http.MediaTypeJSON 51 | } 52 | } 53 | 54 | func WithContentTypeJSON() Option { 55 | return func(headers map[string]string) { 56 | headers["Content-Type"] = http.MediaTypeJSON 57 | } 58 | } 59 | 60 | func WithAcceptJSON() Option { 61 | return func(headers map[string]string) { 62 | headers["Accept"] = http.MediaTypeJSON 63 | } 64 | } 65 | 66 | func WithBearerAuth(token string) Option { 67 | return func(headers map[string]string) { 68 | headers["Authorization"] = fmt.Sprintf("Bearer %s", token) 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /pkg/errors/validation.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package errors 18 | 19 | import ( 20 | "fmt" 21 | "strings" 22 | ) 23 | 24 | type ValidationFailed struct { 25 | validationErrors []string 26 | } 27 | 28 | func (e *ValidationFailed) Error() string { 29 | errorList := strings.Join(e.validationErrors, "\n") 30 | return fmt.Sprintf("Validation failed with the following:\n%s", errorList) 31 | } 32 | 33 | func (e *ValidationFailed) Failures() []string { 34 | return e.validationErrors 35 | } 36 | 37 | func (e *ValidationFailed) AddFailure(failureText string) { 38 | e.validationErrors = append(e.validationErrors, failureText) 39 | } 40 | 41 | func (e *ValidationFailed) setup() { 42 | if e.validationErrors != nil { 43 | return 44 | } 45 | e.validationErrors = []string{} 46 | } 47 | 48 | func IsValidationFailed(err error) bool { 49 | if _, ok := err.(*ValidationFailed); ok { //nolint: errorlint 50 | return true 51 | } 52 | 53 | return false 54 | } 55 | -------------------------------------------------------------------------------- /pkg/flags/flags_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package flags_test 18 | 19 | import ( 20 | "fmt" 21 | "testing" 22 | 23 | . "github.com/onsi/gomega" 24 | "github.com/spf13/pflag" 25 | 26 | "github.com/fidelity/kconnect/pkg/flags" 27 | ) 28 | 29 | func TestExistsWithValue(t *testing.T) { 30 | testCases := []struct { 31 | name string 32 | flag string 33 | flagset *pflag.FlagSet 34 | expect bool 35 | }{ 36 | { 37 | name: "flag doesn't exists in flagset", 38 | flag: "flag1", 39 | flagset: pflag.NewFlagSet("", pflag.PanicOnError), 40 | expect: false, 41 | }, 42 | { 43 | name: "flag exists but value is empty string", 44 | flag: "flag1", 45 | flagset: createTestFlagSet(t, "flag1", ""), 46 | expect: false, 47 | }, 48 | { 49 | name: "flag exists and value is set", 50 | flag: "flag1", 51 | flagset: createTestFlagSet(t, "flag1", "this is set"), 52 | expect: true, 53 | }, 54 | } 55 | 56 | for _, tc := range testCases { 57 | t.Run(tc.name, func(t *testing.T) { 58 | g := NewWithT(t) 59 | 60 | actual := flags.ExistsWithValue(tc.flag, tc.flagset) //nolint:scopelint 61 | g.Expect(actual).To(Equal(tc.expect)) //nolint:scopelint 62 | }) 63 | } 64 | } 65 | 66 | func TestParseFlagMultiValueToMap(t *testing.T) { 67 | testCases := []struct { 68 | name string 69 | flag string 70 | expect map[string]string 71 | }{ 72 | { 73 | name: "flag has no value", 74 | flag: "", 75 | expect: map[string]string{}, 76 | }, 77 | { 78 | name: "flag has 1 value", 79 | flag: "key1=val1", 80 | expect: map[string]string{"key1": "val1"}, 81 | }, 82 | { 83 | name: "flag has multiple value", 84 | flag: "key1=val1,key2=val2", 85 | expect: map[string]string{"key1": "val1", "key2": "val2"}, 86 | }, 87 | } 88 | 89 | for _, tc := range testCases { 90 | t.Run(tc.name, func(t *testing.T) { 91 | g := NewWithT(t) 92 | 93 | actual := flags.ParseFlagMultiValueToMap(tc.flag) 94 | g.Expect(actual).To(Equal(tc.expect)) //nolint:scopelint 95 | }) 96 | } 97 | } 98 | 99 | func createTestFlagSet(t *testing.T, name, value string) *pflag.FlagSet { 100 | fs := pflag.NewFlagSet("", pflag.PanicOnError) 101 | fs.String(name, "", "test flag") 102 | 103 | flagName := fmt.Sprintf("--%s", name) 104 | 105 | if err := fs.Parse([]string{flagName, value}); err != nil { 106 | t.Fatal("error parsing flags") 107 | } 108 | 109 | // Add some other flags 110 | fs.Bool("bflag", true, "some bool flag") 111 | fs.String("sflaf", "hello", "some string flag") 112 | 113 | return fs 114 | } 115 | -------------------------------------------------------------------------------- /pkg/history/filter_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package history 18 | 19 | import ( 20 | "testing" 21 | ) 22 | 23 | func Test_EqualsWithWildcard(t *testing.T) { 24 | testCases := []struct { 25 | name string 26 | filterInput string 27 | input string 28 | expect bool 29 | }{ 30 | { 31 | name: "no wildcards match", 32 | filterInput: "exactmatch", 33 | input: "exactmatch", 34 | expect: true, 35 | }, 36 | { 37 | name: "no wildcards mistmatch", 38 | filterInput: "exactmatch", 39 | input: "nomatch", 40 | expect: false, 41 | }, 42 | { 43 | name: "wildcard match start", 44 | filterInput: "*match", 45 | input: "thisshouldmatch", 46 | expect: true, 47 | }, 48 | { 49 | name: "wildcard mismatch start", 50 | filterInput: "*match", 51 | input: "thisshouldmatchNOT", 52 | expect: false, 53 | }, 54 | { 55 | name: "wildcard match end", 56 | filterInput: "match*", 57 | input: "matchthisshould", 58 | expect: true, 59 | }, 60 | { 61 | name: "wildcard mismatch end", 62 | filterInput: "match*", 63 | input: "thishouldnotmatch", 64 | expect: false, 65 | }, 66 | { 67 | name: "wildcard match start and end", 68 | filterInput: "*match*", 69 | input: "thisshouldmatchitshould", 70 | expect: true, 71 | }, 72 | { 73 | name: "wildcard mismatch start and end", 74 | filterInput: "*match*", 75 | input: "thisshouldnotmaaatchno", 76 | expect: false, 77 | }, 78 | } 79 | 80 | for _, tc := range testCases { 81 | t.Run(tc.name, func(t *testing.T) { 82 | 83 | actual := equalsWithWildcard(tc.filterInput, tc.input) 84 | if actual != tc.expect { 85 | t.Fatalf("expected %t but got %t", tc.expect, actual) 86 | } 87 | }) 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /pkg/history/history.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package history 18 | 19 | import ( 20 | historyv1alpha "github.com/fidelity/kconnect/api/v1alpha1" 21 | ) 22 | 23 | // Store is an interface for the history store 24 | type Store interface { 25 | Add(entry *historyv1alpha.HistoryEntry) error 26 | Remove(entries []*historyv1alpha.HistoryEntry) error 27 | SetHistoryList(historyList *historyv1alpha.HistoryEntryList) error 28 | 29 | GetAll() (*historyv1alpha.HistoryEntryList, error) 30 | GetByID(id string) (*historyv1alpha.HistoryEntry, error) 31 | GetByProvider(providerName string) ([]*historyv1alpha.HistoryEntry, error) 32 | GetByProviderWithID(providerName, providerID string) ([]*historyv1alpha.HistoryEntry, error) 33 | GetByAlias(alias string) (*historyv1alpha.HistoryEntry, error) 34 | GetLastModified(index int) (*historyv1alpha.HistoryEntry, error) 35 | Update(entry *historyv1alpha.HistoryEntry) error 36 | GetAllSortedByLastUsed() (*historyv1alpha.HistoryEntryList, error) 37 | } 38 | -------------------------------------------------------------------------------- /pkg/history/loader/loader.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package loader 18 | 19 | import ( 20 | "fmt" 21 | "io/ioutil" 22 | "os" 23 | "path/filepath" 24 | 25 | "sigs.k8s.io/yaml" 26 | 27 | historyv1alpha "github.com/fidelity/kconnect/api/v1alpha1" 28 | "github.com/fidelity/kconnect/pkg/defaults" 29 | "k8s.io/apimachinery/pkg/runtime" 30 | ) 31 | 32 | type Loader interface { 33 | Load() (*historyv1alpha.HistoryEntryList, error) 34 | 35 | Save(historyList *historyv1alpha.HistoryEntryList) error 36 | } 37 | 38 | func NewFileLoader(path string) (Loader, error) { 39 | if path == "" { 40 | path = defaults.HistoryPath() 41 | } 42 | historyFile, err := filepath.Abs(path) 43 | if err != nil { 44 | return nil, fmt.Errorf("getting absolute file path for %s: %w", path, err) 45 | } 46 | 47 | info, err := os.Stat(historyFile) 48 | if err != nil { 49 | if !os.IsNotExist(err) { 50 | return nil, fmt.Errorf("getting details of file %s: %w", historyFile, err) 51 | } 52 | emptyHistoryFile, err := os.Create(historyFile) 53 | if err != nil { 54 | return nil, fmt.Errorf("creating empty history file %s: %w", historyFile, err) 55 | } 56 | emptyHistoryFile.Close() 57 | 58 | } else if info.IsDir() { 59 | return nil, fmt.Errorf("supplied path is a directory %s: %w", historyFile, err) 60 | } 61 | 62 | return &fileLoader{ 63 | path: historyFile, 64 | }, nil 65 | } 66 | 67 | type fileLoader struct { 68 | path string 69 | } 70 | 71 | func (f *fileLoader) Load() (*historyv1alpha.HistoryEntryList, error) { 72 | data, err := ioutil.ReadFile(f.path) 73 | if err != nil { 74 | return nil, fmt.Errorf("reading file %s: %w", f.path, err) 75 | } 76 | 77 | if len(data) == 0 { 78 | return historyv1alpha.NewHistoryEntryList(), nil 79 | } 80 | 81 | _, historyCodecs, err := historyv1alpha.NewSchemeAndCodecs() 82 | if err != nil { 83 | return nil, fmt.Errorf("getting history codec: %w", err) 84 | } 85 | 86 | historyList := &historyv1alpha.HistoryEntryList{} 87 | if err := runtime.DecodeInto(historyCodecs.UniversalDecoder(), data, historyList); err != nil { 88 | return nil, fmt.Errorf("decoding history file: %w", err) 89 | } 90 | 91 | return historyList, nil 92 | } 93 | 94 | func (f *fileLoader) Save(historyList *historyv1alpha.HistoryEntryList) error { 95 | data, err := yaml.Marshal(historyList) 96 | if err != nil { 97 | return fmt.Errorf("marshalling history list: %w", err) 98 | } 99 | 100 | if err := ioutil.WriteFile(f.path, data, os.ModePerm); err != nil { 101 | return fmt.Errorf("saving history file to %s: %w", f.path, err) 102 | } 103 | 104 | return nil 105 | } 106 | -------------------------------------------------------------------------------- /pkg/history/loader/mock_loader/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Run go generate to generate a mock loader 18 | //go:generate ../../../hack/tools/bin/mockgen -destination loader_mock.go -package mock_loader github.com/fidelity/kconnect/pkg/history/loader Loader 19 | 20 | package mock_loader //nolint: nolintlint 21 | -------------------------------------------------------------------------------- /pkg/history/loader/mock_loader/loader_mock.go: -------------------------------------------------------------------------------- 1 | // Code generated by MockGen. DO NOT EDIT. 2 | // Source: github.com/fidelity/kconnect/pkg/history/loader (interfaces: Loader) 3 | 4 | // Package mock_loader is a generated GoMock package. 5 | package mock_loader 6 | 7 | import ( 8 | v1alpha1 "github.com/fidelity/kconnect/api/v1alpha1" 9 | gomock "github.com/golang/mock/gomock" 10 | reflect "reflect" 11 | ) 12 | 13 | // MockLoader is a mock of Loader interface 14 | type MockLoader struct { 15 | ctrl *gomock.Controller 16 | recorder *MockLoaderMockRecorder 17 | } 18 | 19 | // MockLoaderMockRecorder is the mock recorder for MockLoader 20 | type MockLoaderMockRecorder struct { 21 | mock *MockLoader 22 | } 23 | 24 | // NewMockLoader creates a new mock instance 25 | func NewMockLoader(ctrl *gomock.Controller) *MockLoader { 26 | mock := &MockLoader{ctrl: ctrl} 27 | mock.recorder = &MockLoaderMockRecorder{mock} 28 | return mock 29 | } 30 | 31 | // EXPECT returns an object that allows the caller to indicate expected use 32 | func (m *MockLoader) EXPECT() *MockLoaderMockRecorder { 33 | return m.recorder 34 | } 35 | 36 | // Load mocks base method 37 | func (m *MockLoader) Load() (*v1alpha1.HistoryEntryList, error) { 38 | m.ctrl.T.Helper() 39 | ret := m.ctrl.Call(m, "Load") 40 | ret0, _ := ret[0].(*v1alpha1.HistoryEntryList) 41 | ret1, _ := ret[1].(error) 42 | return ret0, ret1 43 | } 44 | 45 | // Load indicates an expected call of Load 46 | func (mr *MockLoaderMockRecorder) Load() *gomock.Call { 47 | mr.mock.ctrl.T.Helper() 48 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Load", reflect.TypeOf((*MockLoader)(nil).Load)) 49 | } 50 | 51 | // Save mocks base method 52 | func (m *MockLoader) Save(arg0 *v1alpha1.HistoryEntryList) error { 53 | m.ctrl.T.Helper() 54 | ret := m.ctrl.Call(m, "Save", arg0) 55 | ret0, _ := ret[0].(error) 56 | return ret0 57 | } 58 | 59 | // Save indicates an expected call of Save 60 | func (mr *MockLoaderMockRecorder) Save(arg0 interface{}) *gomock.Call { 61 | mr.mock.ctrl.T.Helper() 62 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Save", reflect.TypeOf((*MockLoader)(nil).Save), arg0) 63 | } 64 | -------------------------------------------------------------------------------- /pkg/history/time/time.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package time 18 | 19 | import ( 20 | "time" 21 | 22 | "github.com/fidelity/kconnect/pkg/aws/awsconfig" 23 | "gopkg.in/ini.v1" 24 | ) 25 | 26 | func GetExpireTimeFromAWSCredentials(profileName string) (time.Time, error) { 27 | 28 | path, err := awsconfig.LocateConfigFile() 29 | if err != nil { 30 | return time.Time{}, err 31 | } 32 | cfg, err := ini.Load(path) 33 | if err != nil { 34 | return time.Time{}, err 35 | } 36 | tokenTime := cfg.Section(profileName).Key("x_security_token_expires").String() 37 | return time.Parse(time.RFC3339, tokenTime) 38 | 39 | } 40 | 41 | func GetRemainingTime(expiresAt time.Time) string { 42 | 43 | timeRemaining := time.Until(expiresAt) 44 | timeRemaining = timeRemaining.Round(time.Second) 45 | if timeRemaining.Seconds() < 0 { 46 | timeRemaining = 0 47 | } 48 | return timeRemaining.String() 49 | } 50 | -------------------------------------------------------------------------------- /pkg/http/types.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package http 18 | 19 | const ( 20 | StatusCodeOK = 200 21 | ) 22 | 23 | // Client represents an http client 24 | type Client interface { 25 | Do(req *ClientRequest) (ClientResponse, error) 26 | Get(url string, headers map[string]string) (ClientResponse, error) 27 | Post(url string, body string, headers map[string]string) (ClientResponse, error) 28 | } 29 | 30 | // ClientRequest represents a http request 31 | type ClientRequest struct { 32 | URL string 33 | Body *string 34 | Method string 35 | Headers map[string]string 36 | } 37 | 38 | // ClientResponse represents a http client response 39 | type ClientResponse interface { 40 | ResponseCode() int 41 | Body() string 42 | Headers() map[string]string 43 | } 44 | -------------------------------------------------------------------------------- /pkg/k8s/kubeconfig/kubeconfig.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package kubeconfig 18 | 19 | import ( 20 | "fmt" 21 | 22 | "go.uber.org/zap" 23 | 24 | "k8s.io/client-go/tools/clientcmd" 25 | "k8s.io/client-go/tools/clientcmd/api" 26 | ) 27 | 28 | // Write will write the kubeconfig to the specified file. If there 29 | // is an existing kubeconfig it will be merged if flag is set to true 30 | func Write(path string, clusterConfig *api.Config, merge, setCurrent bool) error { 31 | zap.S().Debugw("writing kubeconfig", "path", path) 32 | 33 | pathOptions := clientcmd.NewDefaultPathOptions() 34 | if path != "" { 35 | pathOptions.LoadingRules.ExplicitPath = path 36 | } 37 | var newConfig *api.Config 38 | if merge { 39 | existingConfig, err := pathOptions.GetStartingConfig() 40 | if err != nil { 41 | return fmt.Errorf("getting existing kubeconfig: %w", err) 42 | } 43 | 44 | zap.S().Debug("merging kubeconfig files") 45 | for k, v := range clusterConfig.Clusters { 46 | existingConfig.Clusters[k] = v 47 | } 48 | for k, v := range clusterConfig.AuthInfos { 49 | existingConfig.AuthInfos[k] = v 50 | } 51 | for k, v := range clusterConfig.Contexts { 52 | existingConfig.Contexts[k] = v 53 | } 54 | newConfig = existingConfig 55 | } else { 56 | newConfig = clusterConfig 57 | } 58 | 59 | if setCurrent { 60 | zap.S().Infow("setting current context", "context", clusterConfig.CurrentContext) 61 | newConfig.CurrentContext = clusterConfig.CurrentContext 62 | } 63 | 64 | if err := clientcmd.ModifyConfig(pathOptions, *newConfig, true); err != nil { 65 | return fmt.Errorf("writing kubeconfig: %w", err) 66 | } 67 | zap.S().Infow("kubeconfig updated", "path", path) 68 | 69 | return nil 70 | } 71 | 72 | func Read(path string) (*api.Config, error) { 73 | 74 | pathOptions := clientcmd.NewDefaultPathOptions() 75 | if path != "" { 76 | pathOptions.LoadingRules.ExplicitPath = path 77 | } 78 | 79 | existingConfig, err := pathOptions.GetStartingConfig() 80 | if err != nil { 81 | return nil, fmt.Errorf("getting existing kubeconfig: %w", err) 82 | } 83 | return existingConfig, nil 84 | } 85 | 86 | func GetCurrentContext(path string) (*api.Context, error) { 87 | 88 | pathOptions := clientcmd.NewDefaultPathOptions() 89 | if path != "" { 90 | pathOptions.LoadingRules.ExplicitPath = path 91 | } 92 | existingConfig, err := pathOptions.GetStartingConfig() 93 | if err != nil { 94 | return nil, fmt.Errorf("getting existing kubeconfig: %w", err) 95 | } 96 | currentContext := existingConfig.Contexts[existingConfig.CurrentContext] 97 | return currentContext, nil 98 | } 99 | -------------------------------------------------------------------------------- /pkg/logging/logging.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package logging 18 | 19 | import ( 20 | "errors" 21 | "fmt" 22 | "log" 23 | "os" 24 | 25 | "github.com/sirupsen/logrus" 26 | "go.uber.org/zap" 27 | "go.uber.org/zap/zapcore" 28 | ) 29 | 30 | const ( 31 | thirdPartyVerboseLevel = 9 32 | ) 33 | 34 | var ( 35 | ErrInvalidFomat = errors.New("invalid log format") 36 | ) 37 | 38 | // Configure will configure the logging for kconnect and the dependent saml2aws package 39 | func Configure(verbosity int) error { 40 | 41 | configureLogrus(verbosity) 42 | 43 | if err := configureZap(verbosity); err != nil { 44 | return fmt.Errorf("configuring zap logging: %w", err) 45 | } 46 | 47 | log.SetOutput(os.Stderr) 48 | log.SetFlags(0) 49 | 50 | return nil 51 | } 52 | 53 | // configureLogrus will configure logrus which is used by saml2aws 54 | func configureLogrus(verbosity int) { 55 | logrus.SetFormatter(&logrus.TextFormatter{DisableTimestamp: true}) 56 | logrus.SetOutput(os.Stderr) 57 | 58 | if verbosity >= thirdPartyVerboseLevel { 59 | logrus.SetLevel(logrus.DebugLevel) 60 | } 61 | } 62 | 63 | func configureZap(verbosity int) error { 64 | logConfig := zap.NewProductionConfig() 65 | 66 | logConfig.Encoding = "console" 67 | logConfig.EncoderConfig.EncodeLevel = zapcore.LowercaseColorLevelEncoder 68 | logConfig.EncoderConfig.TimeKey = "" 69 | logConfig.EncoderConfig.CallerKey = "" 70 | logConfig.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder 71 | 72 | if verbosity > 0 { 73 | logConfig.Level.SetLevel(zap.DebugLevel) 74 | } else { 75 | logConfig.Level.SetLevel(zap.InfoLevel) 76 | } 77 | 78 | loggerMgr, err := logConfig.Build() 79 | if err != nil { 80 | return fmt.Errorf("building zap logger: %w", err) 81 | } 82 | zap.ReplaceGlobals(loggerMgr) 83 | 84 | return nil 85 | } 86 | -------------------------------------------------------------------------------- /pkg/matchers/history.go: -------------------------------------------------------------------------------- 1 | package matchers 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | 7 | "github.com/golang/mock/gomock" 8 | 9 | historyv1alpha "github.com/fidelity/kconnect/api/v1alpha1" 10 | ) 11 | 12 | func MatchHistoryList(expected *historyv1alpha.HistoryEntryList) gomock.Matcher { 13 | return historyListMatcher{expected: expected} 14 | } 15 | 16 | type historyListMatcher struct { 17 | expected *historyv1alpha.HistoryEntryList 18 | } 19 | 20 | func (m historyListMatcher) Matches(x interface{}) bool { 21 | if !reflect.TypeOf(x).AssignableTo(reflect.TypeOf(m.expected)) { 22 | return false 23 | } 24 | 25 | actualHistoryList := x.(*historyv1alpha.HistoryEntryList) 26 | 27 | if len(actualHistoryList.Items) != len(m.expected.Items) { 28 | return false 29 | } 30 | 31 | for index := range actualHistoryList.Items { 32 | actualEntry := actualHistoryList.Items[index] 33 | expectedEntry := m.expected.Items[index] 34 | 35 | if !actualEntry.Equals(&expectedEntry) { 36 | return false 37 | } 38 | } 39 | 40 | return true 41 | } 42 | 43 | func (m historyListMatcher) String() string { 44 | return fmt.Sprintf("is equal to history list %v", m.expected) 45 | } 46 | -------------------------------------------------------------------------------- /pkg/oidc/identity.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package oidc 18 | 19 | const Oidc = "oidc" 20 | 21 | // Identity represents an oidc identity 22 | type Identity struct { 23 | OidcServer string 24 | OidcId string 25 | OidcSecret string 26 | UsePkce string 27 | SkipOidcTlsVerify string 28 | } 29 | 30 | func (i *Identity) Type() string { 31 | return Oidc 32 | } 33 | 34 | func (i *Identity) Name() string { 35 | return Oidc 36 | } 37 | 38 | func (i *Identity) IsExpired() bool { 39 | return true 40 | } 41 | 42 | func (i *Identity) IdentityProviderName() string { 43 | return Oidc 44 | } 45 | -------------------------------------------------------------------------------- /pkg/plugins/discovery/aws/config.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package aws 18 | 19 | import ( 20 | "context" 21 | "encoding/base64" 22 | "fmt" 23 | 24 | "k8s.io/client-go/tools/clientcmd/api" 25 | 26 | "github.com/fidelity/kconnect/pkg/provider/discovery" 27 | ) 28 | 29 | func (p *eksClusterProvider) GetConfig(ctx context.Context, input *discovery.GetConfigInput) (*discovery.GetConfigOutput, error) { 30 | clusterName := fmt.Sprintf("eks-%s", input.Cluster.Name) 31 | userName := p.identity.ProfileName 32 | contextName := fmt.Sprintf("%s@%s", userName, clusterName) 33 | 34 | certData, err := base64.StdEncoding.DecodeString(*input.Cluster.CertificateAuthorityData) 35 | if err != nil { 36 | return nil, fmt.Errorf("decoding certificate: %w", err) 37 | } 38 | 39 | cfg := &api.Config{ 40 | Clusters: map[string]*api.Cluster{ 41 | clusterName: { 42 | Server: *input.Cluster.ControlPlaneEndpoint, 43 | CertificateAuthorityData: certData, 44 | }, 45 | }, 46 | Contexts: map[string]*api.Context{ 47 | contextName: { 48 | Cluster: clusterName, 49 | AuthInfo: userName, 50 | }, 51 | }, 52 | } 53 | 54 | execConfig := &api.ExecConfig{ 55 | APIVersion: "client.authentication.k8s.io/v1beta1", 56 | Command: "aws-iam-authenticator", 57 | Args: []string{ 58 | "token", 59 | "-i", 60 | input.Cluster.Name, 61 | }, 62 | Env: []api.ExecEnvVar{ 63 | { 64 | Name: "AWS_PROFILE", 65 | Value: p.identity.ProfileName, 66 | }, 67 | }, 68 | } 69 | 70 | if p.identity.AWSSharedCredentialsFile != "" { 71 | execConfig.Env = append(execConfig.Env, api.ExecEnvVar{ 72 | Name: "AWS_SHARED_CREDENTIALS_FILE", 73 | Value: p.identity.AWSSharedCredentialsFile, 74 | }) 75 | } 76 | 77 | cfg.AuthInfos = map[string]*api.AuthInfo{ 78 | userName: { 79 | Exec: execConfig, 80 | }, 81 | } 82 | 83 | cfg.CurrentContext = contextName 84 | 85 | if input.Namespace != nil && *input.Namespace != "" { 86 | p.logger.Debugw("setting kubernetes namespace", "namespace", *input.Namespace) 87 | cfg.Contexts[contextName].Namespace = *input.Namespace 88 | } 89 | 90 | return &discovery.GetConfigOutput{ 91 | KubeConfig: cfg, 92 | ContextName: &contextName, 93 | }, nil 94 | } 95 | -------------------------------------------------------------------------------- /pkg/plugins/discovery/aws/discover.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package aws 18 | 19 | import ( 20 | "context" 21 | "fmt" 22 | 23 | awsgo "github.com/aws/aws-sdk-go/aws" 24 | "github.com/aws/aws-sdk-go/service/eks" 25 | 26 | "github.com/fidelity/kconnect/pkg/provider/discovery" 27 | ) 28 | 29 | func (p *eksClusterProvider) Discover(ctx context.Context, input *discovery.DiscoverInput) (*discovery.DiscoverOutput, error) { 30 | if err := p.setup(input.ConfigSet, input.Identity); err != nil { 31 | return nil, fmt.Errorf("setting up eks provider: %w", err) 32 | } 33 | 34 | p.logger.Info("discovering EKS clusters") 35 | 36 | clusters, err := p.listClusters() 37 | if err != nil { 38 | return nil, fmt.Errorf("listing clusters: %w", err) 39 | } 40 | 41 | discoverOutput := &discovery.DiscoverOutput{ 42 | DiscoveryProvider: ProviderName, 43 | IdentityProvider: "aws", 44 | Clusters: make(map[string]*discovery.Cluster), 45 | } 46 | 47 | if len(clusters) == 0 { 48 | p.logger.Info("no EKS clusters discovered") 49 | return discoverOutput, nil 50 | } 51 | 52 | for _, clusterName := range clusters { 53 | clusterDetail, err := p.getClusterConfig(*clusterName) 54 | if err != nil { 55 | return nil, fmt.Errorf("getting cluster config: %w", err) 56 | } 57 | discoverOutput.Clusters[clusterDetail.ID] = clusterDetail 58 | 59 | } 60 | 61 | return discoverOutput, nil 62 | } 63 | 64 | func (p *eksClusterProvider) listClusters() ([]*string, error) { 65 | input := &eks.ListClustersInput{} 66 | 67 | clusters := []*string{} 68 | err := p.eksClient.ListClustersPages(input, func(page *eks.ListClustersOutput, lastPage bool) bool { 69 | clusters = append(clusters, page.Clusters...) 70 | return true 71 | }) 72 | if err != nil { 73 | return nil, fmt.Errorf("listing clusters: %w", err) 74 | } 75 | 76 | return clusters, nil 77 | } 78 | 79 | func (p *eksClusterProvider) getClusterConfig(clusterName string) (*discovery.Cluster, error) { 80 | 81 | input := &eks.DescribeClusterInput{ 82 | Name: awsgo.String(clusterName), 83 | } 84 | 85 | output, err := p.eksClient.DescribeCluster(input) 86 | if err != nil { 87 | return nil, fmt.Errorf("describing cluster %s: %w", clusterName, err) 88 | } 89 | 90 | return &discovery.Cluster{ 91 | ID: *output.Cluster.Arn, 92 | Name: *output.Cluster.Name, 93 | ControlPlaneEndpoint: output.Cluster.Endpoint, 94 | CertificateAuthorityData: output.Cluster.CertificateAuthority.Data, 95 | }, nil 96 | } 97 | -------------------------------------------------------------------------------- /pkg/plugins/discovery/aws/errors.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package aws 18 | 19 | import "errors" 20 | 21 | var ( 22 | ErrNoRoleArnFlag = errors.New("no role-arn flag found in resolver") 23 | ErrNoSession = errors.New("no aws session supplied") 24 | ErrFlagMissing = errors.New("flag missing") 25 | ErrNotAWSIdentity = errors.New("unsupported identity, AWSIdentity required") 26 | ErrUnexpectedClusterFormat = errors.New("cluster name from ARN has unexpected format") 27 | ) 28 | -------------------------------------------------------------------------------- /pkg/plugins/discovery/aws/get.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package aws 18 | 19 | import ( 20 | "context" 21 | "fmt" 22 | "strings" 23 | 24 | "github.com/aws/aws-sdk-go/aws/arn" 25 | 26 | "github.com/fidelity/kconnect/pkg/provider/discovery" 27 | ) 28 | 29 | const ( 30 | expectedNameParts = 2 31 | ) 32 | 33 | // Get will get the details of a EKS cluster. The clusterID maps to a ARN 34 | func (p *eksClusterProvider) GetCluster(ctx context.Context, input *discovery.GetClusterInput) (*discovery.GetClusterOutput, error) { 35 | if err := p.setup(input.ConfigSet, input.Identity); err != nil { 36 | return nil, fmt.Errorf("setting up eks provider: %w", err) 37 | } 38 | 39 | p.logger.Infow("getting EKS cluster", "id", input.ClusterID) 40 | clusterName, err := p.getClusterName(input.ClusterID) 41 | if err != nil { 42 | return nil, fmt.Errorf("getting cluster name for cluster id %s: %w", input.ClusterID, err) 43 | } 44 | 45 | cluster, err := p.getClusterConfig(clusterName) 46 | if err != nil { 47 | return nil, fmt.Errorf("getting cluster config for %s: %w", input.ClusterID, err) 48 | } 49 | 50 | return &discovery.GetClusterOutput{ 51 | Cluster: cluster, 52 | }, nil 53 | } 54 | 55 | func (p *eksClusterProvider) getClusterName(clusterID string) (string, error) { 56 | clusterARN, err := arn.Parse(clusterID) 57 | if err != nil { 58 | return "", fmt.Errorf("parsing cluster id as ARN: %w", err) 59 | } 60 | 61 | parts := strings.Split(clusterARN.Resource, "/") 62 | if len(parts) != expectedNameParts { 63 | return "", ErrUnexpectedClusterFormat 64 | } 65 | 66 | return parts[1], nil 67 | } 68 | -------------------------------------------------------------------------------- /pkg/plugins/discovery/aws/resolver.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package aws 18 | 19 | import ( 20 | "fmt" 21 | 22 | "github.com/fidelity/kconnect/pkg/config" 23 | kerrors "github.com/fidelity/kconnect/pkg/errors" 24 | "github.com/fidelity/kconnect/pkg/provider/identity" 25 | ) 26 | 27 | func (p *eksClusterProvider) Validate(cfg config.ConfigurationSet) error { 28 | errsValidation := &kerrors.ValidationFailed{} 29 | 30 | for _, item := range cfg.GetAll() { 31 | if item.Required && !cfg.ExistsWithValue(item.Name) { 32 | errsValidation.AddFailure(fmt.Sprintf("%s is required", item.Name)) 33 | } 34 | } 35 | 36 | if len(errsValidation.Failures()) > 0 { 37 | return errsValidation 38 | } 39 | 40 | return nil 41 | } 42 | 43 | // Resolve will resolve the values for the AWS specific flags that have no value. It will 44 | // query AWS and interactively ask the user for selections. 45 | func (p *eksClusterProvider) Resolve(config config.ConfigurationSet, userID identity.Identity) error { 46 | return nil 47 | } 48 | -------------------------------------------------------------------------------- /pkg/plugins/discovery/azure/defaults.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package azure 18 | 19 | const ( 20 | TenantIDConfigItem = "tenant-id" 21 | ClientIDConfigItem = "client-id" 22 | AADHostConfigItem = "aad-host" 23 | SubscriptionIDConfigItem = "subscription-id" 24 | SubscriptionNameConfigItem = "subscription-name" 25 | ResourceGroupConfigItem = "resource-group" 26 | AdminConfigItem = "admin" 27 | ClusterNameConfigItem = "cluster-name" 28 | LoginTypeConfigItem = "login-type" 29 | AzureEnvironmentConfigItem = "azure-env" 30 | ServerFqdnTypeConfigItem = "server-fqdn-type" 31 | ) 32 | -------------------------------------------------------------------------------- /pkg/plugins/discovery/azure/errors.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package azure 18 | 19 | import "errors" 20 | 21 | var ( 22 | ErrUnsupportedIdentity = errors.New("unsupported identity, oidc.Identity orazure.AuthorizerIdentity required") 23 | ErrNoKubeconfigs = errors.New("no kubeconfigs available for the managed cluster") 24 | ErrNoSubscriptions = errors.New("no subscriptions found") 25 | ErrSubscriptionNameOrID = errors.New("subscription name and id cannot be both supplied") 26 | ErrSubscriptionNotFound = errors.New("subscription not found") 27 | ErrTokenNeedsAD = errors.New("the 'token' login type requires using aad idp-protocol") 28 | ) 29 | -------------------------------------------------------------------------------- /pkg/plugins/discovery/azure/get.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package azure 18 | 19 | import ( 20 | "context" 21 | "fmt" 22 | 23 | azclient "github.com/fidelity/kconnect/pkg/azure/client" 24 | "github.com/fidelity/kconnect/pkg/azure/id" 25 | "github.com/fidelity/kconnect/pkg/provider/discovery" 26 | ) 27 | 28 | // Get will get the details of a AKS cluster. 29 | func (p *aksClusterProvider) GetCluster(ctx context.Context, input *discovery.GetClusterInput) (*discovery.GetClusterOutput, error) { 30 | if err := p.setup(input.ConfigSet, input.Identity); err != nil { 31 | return nil, fmt.Errorf("setting up aks provider: %w", err) 32 | } 33 | p.logger.Infow("getting AKS cluster", "id", input.ClusterID) 34 | 35 | resourceID, err := id.FromClusterID(input.ClusterID) 36 | if err != nil { 37 | return nil, fmt.Errorf("getting resource id: %w", err) 38 | } 39 | 40 | client := azclient.NewContainerClient(resourceID.SubscriptionID, p.authorizer) 41 | result, err := client.Get(ctx, resourceID.ResourceGroupName, resourceID.ResourceName) 42 | if err != nil { 43 | return nil, fmt.Errorf("getting cluster: %w", err) 44 | } 45 | 46 | cluster := &discovery.Cluster{ 47 | Name: *result.Name, 48 | ID: input.ClusterID, 49 | } 50 | 51 | return &discovery.GetClusterOutput{ 52 | Cluster: cluster, 53 | }, nil 54 | } 55 | -------------------------------------------------------------------------------- /pkg/plugins/discovery/azure/types.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package azure 18 | 19 | // Environment is a type that represents an Azure environment 20 | type Environment string 21 | 22 | var ( 23 | // EnvironmentPublicCloud is the general Azure public cloud 24 | EnvironmentPublicCloud = Environment("public") 25 | // EnvironmentChinaCloud is the public Azure cloud in China 26 | EnvironmentChinaCloud = Environment("china") 27 | // EnvironmentUSGovCloud is the US Government specific Azure cloud 28 | EnvironmentUSGovCloud = Environment("usgov") 29 | // EnvironmentStackCloud is the Azure stack cloud 30 | EnvironmentStackCloud = Environment("stack") 31 | ) 32 | 33 | // LoginType is a type that denotes the type of user login 34 | type LoginType string 35 | 36 | var ( 37 | // LoginTypeDeviceCode is for using a device code to login 38 | LoginTypeDeviceCode = LoginType("devicecode") 39 | // LoginTypeServicePrincipal is for using a service principal to login 40 | LoginTypeServicePrincipal = LoginType("spn") 41 | // LoginTypeResourceOwnerPassword is for using the resource owner password type 42 | LoginTypeResourceOwnerPassword = LoginType("ropc") 43 | // LoginTypeManagedServiceIdentity is for using the managed service identity to login 44 | LoginTypeManagedServiceIdentity = LoginType("msi") 45 | // LoginTypeToken is for an embedded token login type 46 | LoginTypeToken = LoginType("token") 47 | // LoginTypeAzureCli is for an using the azurecli to login 48 | LoginTypeAzureCli = LoginType("azurecli") 49 | ) 50 | -------------------------------------------------------------------------------- /pkg/plugins/discovery/oidc/config.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package oidc 18 | 19 | import ( 20 | "context" 21 | "encoding/base64" 22 | "fmt" 23 | 24 | "github.com/fidelity/kconnect/pkg/oidc" 25 | "github.com/fidelity/kconnect/pkg/provider/discovery" 26 | "k8s.io/client-go/tools/clientcmd/api" 27 | ) 28 | 29 | const True = "true" 30 | 31 | func (p *oidcClusterProvider) GetConfig(ctx context.Context, input *discovery.GetConfigInput) (*discovery.GetConfigOutput, error) { 32 | 33 | clusterName := input.Cluster.Name 34 | userName := p.identity.OidcId 35 | contextName := fmt.Sprintf("%s@%s", userName, clusterName) 36 | 37 | certData, err := base64.StdEncoding.DecodeString(*input.Cluster.CertificateAuthorityData) 38 | if err != nil { 39 | return nil, fmt.Errorf("decoding certificate: %w", err) 40 | } 41 | 42 | oidcID, _ := input.Identity.(*oidc.Identity) 43 | 44 | cfg := &api.Config{ 45 | Clusters: map[string]*api.Cluster{ 46 | clusterName: { 47 | Server: *input.Cluster.ControlPlaneEndpoint, 48 | CertificateAuthorityData: certData, 49 | }, 50 | }, 51 | Contexts: map[string]*api.Context{ 52 | contextName: { 53 | Cluster: clusterName, 54 | AuthInfo: userName, 55 | }, 56 | }, 57 | } 58 | 59 | args := []string{ 60 | "oidc-login", 61 | "get-token", 62 | "--oidc-issuer-url=" + oidcID.OidcServer, 63 | "--oidc-client-id=" + oidcID.OidcId, 64 | } 65 | 66 | if oidcID.UsePkce == True { 67 | args = append(args, "--oidc-use-pkce") 68 | } else { 69 | args = append(args, "--oidc-client-secret="+oidcID.OidcSecret) 70 | } 71 | if oidcID.SkipOidcTlsVerify == True { 72 | args = append(args, "--insecure-skip-tls-verify") 73 | } 74 | 75 | execConfig := &api.ExecConfig{ 76 | APIVersion: "client.authentication.k8s.io/v1beta1", 77 | Command: "kubectl", 78 | Args: args, 79 | InteractiveMode: api.IfAvailableExecInteractiveMode, 80 | } 81 | 82 | cfg.AuthInfos = map[string]*api.AuthInfo{ 83 | userName: { 84 | Exec: execConfig, 85 | }, 86 | } 87 | 88 | cfg.CurrentContext = contextName 89 | 90 | return &discovery.GetConfigOutput{ 91 | KubeConfig: cfg, 92 | ContextName: &contextName, 93 | }, nil 94 | } 95 | -------------------------------------------------------------------------------- /pkg/plugins/discovery/oidc/discover.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package oidc 18 | 19 | import ( 20 | "context" 21 | 22 | "github.com/fidelity/kconnect/pkg/provider/discovery" 23 | ) 24 | 25 | func (p *oidcClusterProvider) Discover(ctx context.Context, input *discovery.DiscoverInput) (*discovery.DiscoverOutput, error) { 26 | 27 | cluster, _ := p.getCluster(ctx) 28 | clusters := make(map[string]*discovery.Cluster) 29 | clusters[cluster.ID] = cluster 30 | discoverOutput := &discovery.DiscoverOutput{ 31 | DiscoveryProvider: ProviderName, 32 | IdentityProvider: "oidc", 33 | Clusters: clusters, 34 | } 35 | 36 | return discoverOutput, nil 37 | } 38 | -------------------------------------------------------------------------------- /pkg/plugins/discovery/oidc/get.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package oidc 18 | 19 | import ( 20 | "context" 21 | 22 | "github.com/fidelity/kconnect/pkg/provider/discovery" 23 | ) 24 | 25 | func (p *oidcClusterProvider) GetCluster(ctx context.Context, input *discovery.GetClusterInput) (*discovery.GetClusterOutput, error) { 26 | cluster, _ := p.getCluster(ctx) 27 | return &discovery.GetClusterOutput{ 28 | Cluster: cluster, 29 | }, nil 30 | } 31 | -------------------------------------------------------------------------------- /pkg/plugins/discovery/oidc/resolver.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package oidc 18 | 19 | import ( 20 | "fmt" 21 | 22 | "github.com/fidelity/kconnect/pkg/config" 23 | "github.com/fidelity/kconnect/pkg/provider/identity" 24 | ) 25 | 26 | func (p *oidcClusterProvider) Validate(cfg config.ConfigurationSet) error { 27 | return nil 28 | } 29 | 30 | // Resolve will resolve the values for the OIDC specific flags that have no value. It will 31 | // read config file and interactively ask the user for selections. 32 | func (p *oidcClusterProvider) Resolve(config config.ConfigurationSet, userID identity.Identity) error { 33 | if err := p.setup(config, userID); err != nil { 34 | return fmt.Errorf("setting up oidc provider: %w", err) 35 | } 36 | return nil 37 | } 38 | -------------------------------------------------------------------------------- /pkg/plugins/discovery/plugins.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package discovery 18 | 19 | import ( 20 | // Initialize the discovery plugins 21 | _ "github.com/fidelity/kconnect/pkg/plugins/discovery/aws" 22 | _ "github.com/fidelity/kconnect/pkg/plugins/discovery/azure" 23 | _ "github.com/fidelity/kconnect/pkg/plugins/discovery/oidc" 24 | _ "github.com/fidelity/kconnect/pkg/plugins/discovery/rancher" 25 | ) 26 | -------------------------------------------------------------------------------- /pkg/plugins/discovery/rancher/errors.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package rancher 18 | 19 | import "errors" 20 | 21 | var ( 22 | ErrGetClusterDetail = errors.New("error querying cluster detail") 23 | ErrGettingClusters = errors.New("error querying clusters") 24 | ErrNoKubeconfigAction = errors.New("no generate kubeconfig action found") 25 | ErrGettingKubeconfig = errors.New("error getting kubeconfig from api") 26 | ErrNoMatchingCluster = errors.New("no clusters found that match name") 27 | ErrMulitpleMatchingCluster = errors.New("multiple clusters found that match name") 28 | ) 29 | -------------------------------------------------------------------------------- /pkg/plugins/discovery/rancher/get.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package rancher 18 | 19 | import ( 20 | "context" 21 | "fmt" 22 | 23 | "github.com/fidelity/kconnect/pkg/provider/discovery" 24 | ) 25 | 26 | // Get will get the details of a Rancher cluster. 27 | func (p *rancherClusterProvider) GetCluster(ctx context.Context, input *discovery.GetClusterInput) (*discovery.GetClusterOutput, error) { 28 | if err := p.setup(input.ConfigSet, input.Identity); err != nil { 29 | return nil, fmt.Errorf("setting up rancher provider: %w", err) 30 | } 31 | p.logger.Infow("getting cluster via Rancher", "id", input.ClusterID) 32 | 33 | p.logger.Debugw("getting cluster details from Rancher api", "cluster", input.ClusterID) 34 | clusterDetail, err := p.getClusterDetails(input.ClusterID) 35 | if err != nil { 36 | return nil, fmt.Errorf("getting cluster detail: %w", err) 37 | } 38 | 39 | cluster := &discovery.Cluster{ 40 | Name: clusterDetail.Name, 41 | ID: input.ClusterID, 42 | } 43 | 44 | return &discovery.GetClusterOutput{ 45 | Cluster: cluster, 46 | }, nil 47 | } 48 | -------------------------------------------------------------------------------- /pkg/plugins/discovery/rancher/resolver.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package rancher 18 | 19 | import ( 20 | "fmt" 21 | 22 | "github.com/fidelity/kconnect/pkg/config" 23 | kerrors "github.com/fidelity/kconnect/pkg/errors" 24 | "github.com/fidelity/kconnect/pkg/provider/identity" 25 | rshared "github.com/fidelity/kconnect/pkg/rancher" 26 | ) 27 | 28 | func (p *rancherClusterProvider) Validate(cfg config.ConfigurationSet) error { 29 | errsValidation := &kerrors.ValidationFailed{} 30 | 31 | for _, item := range cfg.GetAll() { 32 | if item.Required && !cfg.ExistsWithValue(item.Name) { 33 | errsValidation.AddFailure(fmt.Sprintf("%s is required", item.Name)) 34 | } 35 | } 36 | 37 | if len(errsValidation.Failures()) > 0 { 38 | return errsValidation 39 | } 40 | 41 | return nil 42 | } 43 | 44 | // Resolve will resolve the values for the Rancher specific flags that have no value. It will 45 | // query Rancher and interactively ask the user for selections. 46 | func (p *rancherClusterProvider) Resolve(cfg config.ConfigurationSet, identity identity.Identity) error { 47 | if err := p.setup(cfg, identity); err != nil { 48 | return fmt.Errorf("setting up rancher provider: %w", err) 49 | } 50 | p.logger.Debug("resolving Rancher configuration items") 51 | 52 | if err := rshared.ResolveCommon(cfg); err != nil { 53 | return fmt.Errorf("resolving common Rancher config: %w", err) 54 | } 55 | 56 | return nil 57 | } 58 | -------------------------------------------------------------------------------- /pkg/plugins/discovery/rancher/types.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package rancher 18 | 19 | type listClustersResponse struct { 20 | Clusters []clusterDetails `json:"data"` 21 | } 22 | 23 | type clusterDetails struct { 24 | ID string `json:"id"` 25 | Name string `json:"name"` 26 | Description string `json:"description"` 27 | EngineConfig *kubernetesEngineConfig `json:"rancherKuernetesEngineConfig,omitempty"` 28 | Actions map[string]string `json:"actions"` 29 | } 30 | 31 | type kubernetesEngineConfig struct { 32 | Version string `json:"kubernetesVersion"` 33 | } 34 | 35 | type generateKubeConfigResponse struct { 36 | Config string `json:"config"` 37 | } 38 | -------------------------------------------------------------------------------- /pkg/plugins/identity/azure/aad/resolver.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package aad 18 | 19 | import ( 20 | "fmt" 21 | 22 | "github.com/fidelity/kconnect/pkg/azure/identity" 23 | "github.com/fidelity/kconnect/pkg/config" 24 | "github.com/fidelity/kconnect/pkg/defaults" 25 | "github.com/fidelity/kconnect/pkg/plugins/discovery/azure" 26 | "github.com/fidelity/kconnect/pkg/prompt" 27 | ) 28 | 29 | func (p *aadIdentityProvider) resolveConfig(cfg config.ConfigurationSet) error { 30 | if !p.interactive { 31 | p.logger.Debug("skipping configuration resolution as runnning non-interactive") 32 | return nil 33 | } 34 | 35 | if err := prompt.InputAndSet(cfg, defaults.UsernameConfigItem, "Username:", true); err != nil { 36 | return fmt.Errorf("resolving %s: %w", defaults.UsernameConfigItem, err) 37 | } 38 | if err := prompt.InputSensitiveAndSet(cfg, defaults.PasswordConfigItem, "Password:", true); err != nil { 39 | return fmt.Errorf("resolving %s: %w", defaults.PasswordConfigItem, err) 40 | } 41 | if err := prompt.InputAndSet(cfg, azure.TenantIDConfigItem, "Enter the Azure tenant ID", true); err != nil { 42 | return fmt.Errorf("resolving %s: %w", azure.TenantIDConfigItem, err) 43 | } 44 | if err := prompt.InputAndSet(cfg, azure.ClientIDConfigItem, "Enter the Azure client ID", true); err != nil { 45 | return fmt.Errorf("resolving %s: %w", azure.ClientIDConfigItem, err) 46 | } 47 | if err := prompt.ChooseAndSet(cfg, azure.AADHostConfigItem, "Choose the Azure AAD host", true, aadHostOptions); err != nil { 48 | return fmt.Errorf("resolving %s: %w", azure.ClientIDConfigItem, err) 49 | } 50 | 51 | return nil 52 | } 53 | 54 | func aadHostOptions() (map[string]string, error) { 55 | return map[string]string{ 56 | "Worldwide (recommended)": string(identity.AADHostWorldwide), 57 | "China": string(identity.AADHostChina), 58 | "Germany": string(identity.AADHostGermany), 59 | "US Gov": string(identity.AADHostUSGov), 60 | "US Gov (API)": string(identity.AADHostUSGovAPI), 61 | "US Gov (Legacy)": string(identity.AADHostUSGovLegacy), 62 | "Fallback": string(identity.AADHostFallback), 63 | }, nil 64 | } 65 | -------------------------------------------------------------------------------- /pkg/plugins/identity/plugins.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package discovery 18 | 19 | import ( 20 | // Initialize the identity plugins 21 | _ "github.com/fidelity/kconnect/pkg/plugins/identity/aws/iam" 22 | _ "github.com/fidelity/kconnect/pkg/plugins/identity/azure/aad" 23 | _ "github.com/fidelity/kconnect/pkg/plugins/identity/azure/env" 24 | _ "github.com/fidelity/kconnect/pkg/plugins/identity/oidc" 25 | _ "github.com/fidelity/kconnect/pkg/plugins/identity/rancher/activedirectory" 26 | _ "github.com/fidelity/kconnect/pkg/plugins/identity/saml" 27 | _ "github.com/fidelity/kconnect/pkg/plugins/identity/static/token" 28 | ) 29 | -------------------------------------------------------------------------------- /pkg/plugins/identity/rancher/activedirectory/resolver.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package activedirectory 18 | 19 | import ( 20 | "fmt" 21 | 22 | "github.com/fidelity/kconnect/pkg/config" 23 | "github.com/fidelity/kconnect/pkg/defaults" 24 | "github.com/fidelity/kconnect/pkg/prompt" 25 | rshared "github.com/fidelity/kconnect/pkg/rancher" 26 | ) 27 | 28 | func (p *radIdentityProvider) resolveConfig(cfg config.ConfigurationSet) error { 29 | if !p.interactive { 30 | p.logger.Debug("skipping configuration resolution as runnning non-interactive") 31 | return nil 32 | } 33 | 34 | if err := prompt.InputAndSet(cfg, defaults.UsernameConfigItem, "Username:", true); err != nil { 35 | return fmt.Errorf("resolving %s: %w", defaults.UsernameConfigItem, err) 36 | } 37 | if err := prompt.InputSensitiveAndSet(cfg, defaults.PasswordConfigItem, "Password:", true); err != nil { 38 | return fmt.Errorf("resolving %s: %w", defaults.PasswordConfigItem, err) 39 | } 40 | if err := rshared.ResolveCommon(cfg); err != nil { 41 | return fmt.Errorf("resolving common Rancher config: %w", err) 42 | } 43 | 44 | return nil 45 | } 46 | -------------------------------------------------------------------------------- /pkg/plugins/identity/rancher/activedirectory/types.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package activedirectory 18 | 19 | import "encoding/json" 20 | 21 | type loginRequest struct { 22 | Type string `json:"type"` 23 | Description string `json:"description"` 24 | Username string `json:"username"` 25 | Password string `json:"password"` 26 | } 27 | 28 | type loginResponse struct { //TODO: add additional fields 29 | Type string `json:"type"` 30 | Name string `json:"name"` 31 | Token string `json:"token"` 32 | UserID string `json:"userId"` 33 | TTL json.Number `json:"ttl"` 34 | } 35 | -------------------------------------------------------------------------------- /pkg/plugins/identity/saml/sp/aws/resolver.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package aws 18 | 19 | import ( 20 | "fmt" 21 | 22 | kaws "github.com/fidelity/kconnect/pkg/aws" 23 | "github.com/fidelity/kconnect/pkg/config" 24 | "github.com/fidelity/kconnect/pkg/defaults" 25 | "github.com/fidelity/kconnect/pkg/prompt" 26 | "github.com/versent/saml2aws/v2" 27 | ) 28 | 29 | // ResolveConfiguration will resolve the values for the AWS specific config items that have no value. 30 | // It will query AWS and interactively ask the user for selections. 31 | func (p *ServiceProvider) ResolveConfiguration(cfg config.ConfigurationSet) error { 32 | p.logger.Debug("resolving AWS identity configuration items") 33 | 34 | // NOTE: resolution is only needed for required fields 35 | if err := p.resolveIdpProvider("idp-provider", cfg); err != nil { 36 | return fmt.Errorf("resolving idp-provider: %w", err) 37 | } 38 | if err := p.resolveIdpEndpoint("idp-endpoint", cfg); err != nil { 39 | return fmt.Errorf("resolving idp-endpoint: %w", err) 40 | } 41 | 42 | if err := kaws.ResolvePartition(cfg); err != nil { 43 | return fmt.Errorf("resolving partition: %w", err) 44 | } 45 | if err := kaws.ResolveRegion(cfg); err != nil { 46 | return fmt.Errorf("resolving region: %w", err) 47 | } 48 | if err := prompt.InputAndSet(cfg, defaults.UsernameConfigItem, "Username:", true); err != nil { 49 | return fmt.Errorf("resolving %s: %w", defaults.UsernameConfigItem, err) 50 | } 51 | if err := prompt.InputSensitiveAndSet(cfg, defaults.PasswordConfigItem, "Password:", true); err != nil { 52 | return fmt.Errorf("resolving %s: %w", defaults.PasswordConfigItem, err) 53 | } 54 | 55 | return nil 56 | } 57 | 58 | func (p *ServiceProvider) resolveIdpEndpoint(name string, cfg config.ConfigurationSet) error { 59 | return prompt.InputAndSet(cfg, name, "Enter the endpoint for the IdP", true) 60 | } 61 | 62 | func (p *ServiceProvider) resolveIdpProvider(name string, cfg config.ConfigurationSet) error { 63 | options := saml2aws.MFAsByProvider.Names() 64 | return prompt.ChooseAndSet(cfg, name, "Select your identity provider", true, prompt.OptionsFromStringSlice(options)) 65 | } 66 | -------------------------------------------------------------------------------- /pkg/plugins/identity/saml/sp/types.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package sp 18 | 19 | import ( 20 | "github.com/versent/saml2aws/v2/pkg/cfg" 21 | 22 | "github.com/fidelity/kconnect/pkg/config" 23 | "github.com/fidelity/kconnect/pkg/provider/common" 24 | "github.com/fidelity/kconnect/pkg/provider/identity" 25 | ) 26 | 27 | type ProviderConfig struct { 28 | common.IdentityProviderConfig 29 | IdpEndpoint string `json:"idp-endpoint" validate:"required"` 30 | IdpProvider string `json:"idp-provider" validate:"required"` 31 | } 32 | 33 | type ServiceProvider interface { 34 | ConfigurationItems() config.ConfigurationSet 35 | 36 | Validate(configItems config.ConfigurationSet) error 37 | ResolveConfiguration(configItems config.ConfigurationSet) error 38 | PopulateAccount(account *cfg.IDPAccount, configItems config.ConfigurationSet) error 39 | ProcessAssertions(account *cfg.IDPAccount, samlAssertions string, configItems config.ConfigurationSet) (identity.Identity, error) 40 | } 41 | -------------------------------------------------------------------------------- /pkg/plugins/plugins.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package plugins 18 | 19 | import ( 20 | // Initialize all the identity, discovery and resolver plugins 21 | _ "github.com/fidelity/kconnect/pkg/plugins/discovery" 22 | _ "github.com/fidelity/kconnect/pkg/plugins/identity" 23 | ) 24 | -------------------------------------------------------------------------------- /pkg/provider/config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "github.com/fidelity/kconnect/pkg/config" 5 | "github.com/fidelity/kconnect/pkg/provider/identity" 6 | ) 7 | 8 | // Resolver is an interface that indicates that the plugin can resolve and validate configuration 9 | type Resolver interface { 10 | 11 | // Validate is used to validate the config items and return any errors 12 | Validate(config config.ConfigurationSet) error 13 | 14 | // Resolve will resolve the values for the supplied config items. It will interactively 15 | // resolve the values by asking the user for selections. 16 | Resolve(config config.ConfigurationSet, identity identity.Identity) error 17 | } 18 | -------------------------------------------------------------------------------- /pkg/provider/discovery/discovery.go: -------------------------------------------------------------------------------- 1 | package discovery 2 | 3 | import ( 4 | "context" 5 | 6 | "k8s.io/client-go/tools/clientcmd/api" 7 | 8 | "github.com/fidelity/kconnect/pkg/config" 9 | "github.com/fidelity/kconnect/pkg/provider" 10 | provcfg "github.com/fidelity/kconnect/pkg/provider/config" 11 | "github.com/fidelity/kconnect/pkg/provider/identity" 12 | ) 13 | 14 | // Provider is the interface that is used to implement providers 15 | // of Kubernetes clusters. Its the job of the provider to 16 | // discover clusters based on a users identity and to generate 17 | // a kubeconfig (and any other files) that are required to access 18 | // a selected cluster. 19 | type Provider interface { 20 | provider.Plugin 21 | provider.PluginPreReqs 22 | provcfg.Resolver 23 | 24 | // Discover will discover what clusters the supplied identity has access to 25 | Discover(ctx context.Context, input *DiscoverInput) (*DiscoverOutput, error) 26 | 27 | // Get will get the details of a cluster with the provided provider 28 | // specific cluster id 29 | GetCluster(ctx context.Context, input *GetClusterInput) (*GetClusterOutput, error) 30 | 31 | // GetClusterConfig will get the kubeconfig for a cluster 32 | GetConfig(ctx context.Context, input *GetConfigInput) (*GetConfigOutput, error) 33 | } 34 | 35 | type ProviderCreatorFun func(input *provider.PluginCreationInput) (Provider, error) 36 | 37 | // DiscoverInput is the input to Discover 38 | type DiscoverInput struct { 39 | ConfigSet config.ConfigurationSet 40 | Identity identity.Identity 41 | } 42 | 43 | // DiscoverOutput holds details of the output of the Discover 44 | type DiscoverOutput struct { 45 | DiscoveryProvider string `yaml:"discoveryProvider"` 46 | IdentityProvider string `yaml:"identityProvider"` 47 | 48 | Clusters map[string]*Cluster `yaml:"clusters"` 49 | } 50 | 51 | // GetClusterInput is the input to GetCluster 52 | type GetClusterInput struct { 53 | ClusterID string 54 | ConfigSet config.ConfigurationSet 55 | Identity identity.Identity 56 | } 57 | 58 | // GetClusterOutput is the output to GetCluster 59 | type GetClusterOutput struct { 60 | Cluster *Cluster 61 | } 62 | 63 | type GetConfigInput struct { 64 | Cluster *Cluster 65 | Namespace *string 66 | Identity identity.Identity 67 | } 68 | 69 | type GetConfigOutput struct { 70 | KubeConfig *api.Config 71 | ContextName *string 72 | } 73 | 74 | // Cluster represents the information about a discovered k8s cluster 75 | type Cluster struct { 76 | ID string `yaml:"id"` 77 | Name string `yaml:"name"` 78 | ControlPlaneEndpoint *string `yaml:"endpoint"` 79 | CertificateAuthorityData *string `yaml:"ca"` 80 | } 81 | -------------------------------------------------------------------------------- /pkg/provider/errors.go: -------------------------------------------------------------------------------- 1 | package provider 2 | 3 | import "errors" 4 | 5 | var ( 6 | ErrHTTPClientRequired = errors.New("http client required") 7 | ) 8 | -------------------------------------------------------------------------------- /pkg/provider/identity/identity.go: -------------------------------------------------------------------------------- 1 | package identity 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/fidelity/kconnect/pkg/config" 7 | "github.com/fidelity/kconnect/pkg/provider" 8 | ) 9 | 10 | // Provider represents the interface used to implement an identity provider 11 | // plugin. It provides authentication functionality. 12 | type Provider interface { 13 | provider.Plugin 14 | 15 | // Authenticate will authenticate a user and return details of their identity. 16 | Authenticate(ctx context.Context, input *AuthenticateInput) (*AuthenticateOutput, error) 17 | } 18 | 19 | type ProviderCreatorFun func(input *provider.PluginCreationInput) (Provider, error) 20 | 21 | type AuthenticateInput struct { 22 | ConfigSet config.ConfigurationSet 23 | } 24 | 25 | type AuthenticateOutput struct { 26 | Identity Identity 27 | } 28 | 29 | // Identity represents a users identity for use with discovery. 30 | // NOTE: details of this need finalising 31 | type Identity interface { 32 | Type() string 33 | Name() string 34 | IsExpired() bool 35 | IdentityProviderName() string 36 | } 37 | 38 | // Store represents an way to store and retrieve credentials 39 | type Store interface { 40 | CredsExists() (bool, error) 41 | Save(identity Identity) error 42 | Load() (Identity, error) 43 | Expired() bool 44 | } 45 | -------------------------------------------------------------------------------- /pkg/provider/identity/token.go: -------------------------------------------------------------------------------- 1 | package identity 2 | 3 | import "errors" 4 | 5 | var ( 6 | ErrNotTokenIdentity = errors.New("not a token identity") 7 | ) 8 | 9 | type TokenIdentity struct { 10 | token string 11 | name string 12 | idProviderName string 13 | } 14 | 15 | func NewTokenIdentity(name, token, idProviderName string) *TokenIdentity { 16 | return &TokenIdentity{ 17 | token: token, 18 | name: name, 19 | idProviderName: idProviderName, 20 | } 21 | } 22 | 23 | func (t *TokenIdentity) Type() string { 24 | return "token" 25 | } 26 | 27 | func (t *TokenIdentity) Name() string { 28 | return t.name 29 | } 30 | 31 | func (t *TokenIdentity) IsExpired() bool { 32 | // TODO: handle properly 33 | return false 34 | } 35 | 36 | func (t *TokenIdentity) IdentityProviderName() string { 37 | return t.idProviderName 38 | } 39 | 40 | func (t *TokenIdentity) Token() string { 41 | return t.token 42 | } 43 | -------------------------------------------------------------------------------- /pkg/provider/selection.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package provider 18 | 19 | import ( 20 | "fmt" 21 | "sort" 22 | 23 | "github.com/fidelity/kconnect/pkg/prompt" 24 | ) 25 | 26 | // SelectItemFunc is a function that is used abstract the method for selecting 27 | // an item from the a list of possible values. Providers shouldn't directly 28 | // ask the user for input and instead should use this. 29 | type SelectItemFunc func(prompt string, items map[string]string) (string, error) 30 | 31 | func DefaultItemSelection(promptMessage string, items map[string]string) (string, error) { 32 | options := []string{} 33 | 34 | for key := range items { 35 | options = append(options, key) 36 | } 37 | if len(options) == 1 { 38 | return items[options[0]], nil 39 | } 40 | 41 | sort.Strings(options) 42 | selectedItem, err := prompt.Choose("item", promptMessage, true, prompt.OptionsFromMap(items)) 43 | if err != nil { 44 | return "", fmt.Errorf("selecting item: %w", err) 45 | } 46 | 47 | return items[selectedItem], nil 48 | } 49 | -------------------------------------------------------------------------------- /pkg/provider/types.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package provider 18 | 19 | import ( 20 | "go.uber.org/zap" 21 | 22 | "github.com/fidelity/kconnect/pkg/config" 23 | khttp "github.com/fidelity/kconnect/pkg/http" 24 | ) 25 | 26 | // Plugin is an interface that can be implemented for returned usage information 27 | type Plugin interface { 28 | // Name returns the name of the plugin 29 | Name() string 30 | } 31 | 32 | // PluginPreReqs is an interface that providers have implement to 33 | // indicate that they have pre-requisites that they can check for 34 | type PluginPreReqs interface { 35 | ListPreReqs() []*PreReq 36 | CheckPreReqs() error 37 | } 38 | 39 | // PreReq represents a pre-requisite 40 | type PreReq interface { 41 | Name() string 42 | Help() string 43 | Check() error 44 | } 45 | 46 | // PluginCreationInput is the input to plugin Init 47 | type PluginCreationInput struct { 48 | Logger *zap.SugaredLogger 49 | IsInteractice bool 50 | ItemSelector SelectItemFunc 51 | ScopedTo *string 52 | HTTPClient khttp.Client 53 | } 54 | 55 | // ConfigurationItemsFunc is a function type that gets configuration items. 56 | // The scopeTo will indicate if there is additional scope that is needed 57 | type ConfigurationItemsFunc func(scopeTo string) (config.ConfigurationSet, error) 58 | -------------------------------------------------------------------------------- /pkg/rancher/config.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package rancher 18 | 19 | import ( 20 | "fmt" 21 | 22 | "github.com/fidelity/kconnect/pkg/config" 23 | ) 24 | 25 | const ( 26 | // APIEndpointConfigName is the name of the config item for the Rancher API endpoint 27 | APIEndpointConfigName = "api-endpoint" 28 | // ClusterName is the user friendly name of the Rancher cluster to connect to 29 | ClusterName = "cluster-name" 30 | ) 31 | 32 | // CommonConfig represents the common configuration for Rancher 33 | type CommonConfig struct { 34 | // APIEndpoint is the URL for the rancher API endpoint 35 | APIEndpoint string `json:"api-endpoint" validate:"required"` 36 | } 37 | 38 | // UseConfig represents the use configuration for Rancher 39 | type UseConfig struct { 40 | // ClusterName is the user friendly name of the Rancher cluster to connect to 41 | ClusterName string `json:"cluster-name"` 42 | } 43 | 44 | // AddCommonConfig adds the Rancher common configuration to a configuration set 45 | func AddCommonConfig(cs config.ConfigurationSet) error { 46 | if _, err := cs.String(APIEndpointConfigName, "", "The Rancher API endpoint"); err != nil { 47 | return fmt.Errorf("setting config item %s: %w", APIEndpointConfigName, err) 48 | } 49 | if err := cs.SetRequired(APIEndpointConfigName); err != nil { 50 | return fmt.Errorf("setting %s required: %w", APIEndpointConfigName, err) 51 | } 52 | return nil 53 | } 54 | 55 | // AddUseConfig adds the Rancher use configuration to a configuration set 56 | func AddUseConfig(cs config.ConfigurationSet) error { 57 | if _, err := cs.String(ClusterName, "", "The Rancher user friendly cluster name"); err != nil { 58 | return fmt.Errorf("setting config item %s: %w", ClusterName, err) 59 | } 60 | return nil 61 | } 62 | -------------------------------------------------------------------------------- /pkg/rancher/endpoints.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package rancher 18 | 19 | import ( 20 | "fmt" 21 | "strings" 22 | ) 23 | 24 | const ( 25 | adAuthTemplate = "%s-public/activeDirectoryProviders/activedirectory?action=login" 26 | clustersTemplate = "%s/clusters" 27 | clusterTemplate = "%s/clusters/%s" 28 | ) 29 | 30 | type EndpointsResolver interface { 31 | ActiveDirectoryAuth() string 32 | ClustersList() string 33 | Cluster(clusterName string) string 34 | } 35 | 36 | func NewStaticEndpointsResolver(apiEndpoint string) (EndpointsResolver, error) { 37 | if apiEndpoint == "" { 38 | return nil, ErrNoAPIEndpoint 39 | } 40 | 41 | if !strings.HasSuffix(apiEndpoint, "/") { 42 | apiEndpoint = strings.TrimSuffix(apiEndpoint, "/") 43 | } 44 | 45 | return &StaticEndpointsResolver{ 46 | apiEndpoint: apiEndpoint, 47 | }, nil 48 | } 49 | 50 | type StaticEndpointsResolver struct { 51 | apiEndpoint string 52 | } 53 | 54 | func (r *StaticEndpointsResolver) ActiveDirectoryAuth() string { 55 | return fmt.Sprintf(adAuthTemplate, r.apiEndpoint) 56 | } 57 | 58 | func (r *StaticEndpointsResolver) ClustersList() string { 59 | return fmt.Sprintf(clustersTemplate, r.apiEndpoint) 60 | } 61 | 62 | func (r *StaticEndpointsResolver) Cluster(clusterName string) string { 63 | return fmt.Sprintf(clusterTemplate, r.apiEndpoint, clusterName) 64 | } 65 | -------------------------------------------------------------------------------- /pkg/rancher/errors.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package rancher 18 | 19 | import "errors" 20 | 21 | var ( 22 | ErrNoAPIEndpoint = errors.New("no rancher api endpoint") 23 | ) 24 | -------------------------------------------------------------------------------- /pkg/rancher/resolve.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package rancher 18 | 19 | import ( 20 | "fmt" 21 | 22 | "github.com/fidelity/kconnect/pkg/config" 23 | "github.com/fidelity/kconnect/pkg/prompt" 24 | ) 25 | 26 | // ResolveCommon will interactively resolve the common configuration for rancher 27 | func ResolveCommon(cfg config.ConfigurationSet) error { 28 | if err := prompt.InputAndSet(cfg, APIEndpointConfigName, "Enter the Rancher API endpoint", true); err != nil { 29 | return fmt.Errorf("resolving %s: %w", APIEndpointConfigName, err) 30 | } 31 | 32 | return nil 33 | } 34 | -------------------------------------------------------------------------------- /pkg/utils/command.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | http://www.apache.org/licenses/LICENSE-2.0 7 | Unless required by applicable law or agreed to in writing, software 8 | distributed under the License is distributed on an "AS IS" BASIS, 9 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | See the License for the specific language governing permissions and 11 | limitations under the License. 12 | */ 13 | 14 | package utils 15 | 16 | import ( 17 | "os" 18 | "path/filepath" 19 | "strings" 20 | 21 | "github.com/spf13/cobra" 22 | ) 23 | 24 | func FormatCommand(cmd *cobra.Command) { 25 | 26 | rootCmdName := "kconnect" 27 | // If running as a krew plugin, need to change usage output 28 | if isKrewPlugin() { 29 | rootCmdName = "kubectl connect" 30 | // Only change this for root command 31 | if cmd.Use == "kconnect" { 32 | cmd.Use = "connect" 33 | } 34 | cmd.SetUsageTemplate(strings.NewReplacer( 35 | "{{.UseLine}}", "kubectl {{.UseLine}}", 36 | "{{.CommandPath}}", "kubectl {{.CommandPath}}").Replace(cmd.UsageTemplate())) 37 | } 38 | cmd.Example = formatMessage(cmd.Example, rootCmdName) 39 | } 40 | 41 | func FormatUse(use string) string { 42 | if isKrewPlugin() { 43 | return "kubectl " + use 44 | } 45 | return use 46 | } 47 | 48 | func isKrewPlugin() bool { 49 | return strings.HasPrefix(filepath.Base(os.Args[0]), "kubectl-") 50 | } 51 | 52 | func formatMessage(message, rootCmdName string) string { 53 | return strings.NewReplacer("{{.CommandPath}}", rootCmdName).Replace(message) 54 | } 55 | -------------------------------------------------------------------------------- /pkg/utils/filter.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | http://www.apache.org/licenses/LICENSE-2.0 7 | Unless required by applicable law or agreed to in writing, software 8 | distributed under the License is distributed on an "AS IS" BASIS, 9 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | See the License for the specific language governing permissions and 11 | limitations under the License. 12 | */ 13 | 14 | package utils 15 | 16 | import ( 17 | "regexp" 18 | "strings" 19 | ) 20 | 21 | // SurveyFilter a function for passing to AlecAivazis/survey, which will allow wildcards(*) and whitespace to be used for subfilter values 22 | func SurveyFilter(filter string, value string, index int) bool { 23 | parsedFilter := regexp.MustCompile(`[\s]+`).ReplaceAllString(filter, "*") 24 | subFilters := strings.Split(parsedFilter, "*") 25 | for _, s := range subFilters { 26 | if !strings.Contains(strings.ToLower(value), strings.ToLower(s)) && s != "" { 27 | return false 28 | } 29 | } 30 | return true 31 | } 32 | 33 | // RegexFilter to filter a slice or strings based on a regex filter passed to it. Returns an error if regex is invalid 34 | func RegexFilter(options []string, regexString string) ([]string, error) { 35 | 36 | var filteredOptions []string 37 | reg, err := regexp.Compile(regexString) 38 | if err != nil { 39 | return filteredOptions, err 40 | } 41 | for _, opt := range options { 42 | if reg.MatchString(opt) { 43 | filteredOptions = append(filteredOptions, opt) 44 | } 45 | } 46 | return filteredOptions, nil 47 | } 48 | -------------------------------------------------------------------------------- /pkg/utils/prerequisites.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The kconnect Authors. 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | http://www.apache.org/licenses/LICENSE-2.0 7 | Unless required by applicable law or agreed to in writing, software 8 | distributed under the License is distributed on an "AS IS" BASIS, 9 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | See the License for the specific language governing permissions and 11 | limitations under the License. 12 | */ 13 | 14 | package utils 15 | 16 | import ( 17 | "encoding/json" 18 | "errors" 19 | "fmt" 20 | "os/exec" 21 | 22 | "golang.org/x/mod/semver" 23 | ) 24 | 25 | const minKubectlVersion string = "v1.17.0" 26 | 27 | var ErrorTooLowKubectlVersion = errors.New("kubectl version is too low") 28 | 29 | type KubectlVersion struct { 30 | ClientVersion struct { 31 | Major string `json:"major"` 32 | Minor string `json:"minor"` 33 | GitVersion string `json:"gitVersion"` 34 | } `json:"clientVersion"` 35 | } 36 | 37 | func CheckKubectlPrereq() error { 38 | 39 | cmd := exec.Command("kubectl", "version", "--output=json", "--client=true") 40 | output, err := cmd.Output() 41 | if err != nil { 42 | return fmt.Errorf("error finding kubectl: %w", err) 43 | } 44 | var kubectlVersion KubectlVersion 45 | err = json.Unmarshal(output, &kubectlVersion) 46 | if err != nil { 47 | return err 48 | } 49 | if err != nil { 50 | return fmt.Errorf("error checking for kubectl: %w", err) 51 | } else if semver.Compare(kubectlVersion.ClientVersion.GitVersion, minKubectlVersion) < 0 { 52 | return ErrorTooLowKubectlVersion 53 | } 54 | return nil 55 | } 56 | 57 | func CheckAWSIAMAuthPrereq() error { 58 | 59 | cmd := exec.Command("aws-iam-authenticator") 60 | _, err := cmd.Output() 61 | if err != nil { 62 | return fmt.Errorf("error finding aws-iam-authenticator: %w", err) 63 | } 64 | return nil 65 | } 66 | 67 | func CheckKubeloginPrereq() error { 68 | 69 | cmd := exec.Command("kubelogin") 70 | _, err := cmd.Output() 71 | if err != nil { 72 | return fmt.Errorf("error finding kubelogin: %w", err) 73 | } 74 | return nil 75 | } 76 | 77 | func CheckKubectlOidcLoginPrereq() error { 78 | 79 | cmd := exec.Command("kubectl", "oidc-login", "version") 80 | _, err := cmd.Output() 81 | if err != nil { 82 | return fmt.Errorf("error finding kubectl oidc-login: %w", err) 83 | } 84 | return nil 85 | } 86 | --------------------------------------------------------------------------------