├── .github ├── ISSUE_TEMPLATE │ ├── bug-report.yaml │ └── enhancement.yaml ├── PULL_REQUEST_TEMPLATE.md └── workflows │ ├── ci-bot.yml │ ├── releases-images.yml │ ├── releases-package.yml │ ├── releases-source.yml │ └── verify.yml ├── .gitignore ├── Makefile ├── OWNERS ├── README.md ├── deb ├── kubeadm │ ├── debian │ │ ├── changelog │ │ ├── compat │ │ ├── control │ │ ├── copyright │ │ ├── kubeadm.install │ │ ├── postinst │ │ ├── rules │ │ └── source │ │ │ └── format │ └── etc │ │ └── systemd │ │ └── system │ │ └── kubelet.service.d │ │ └── 10-kubeadm.conf ├── kubectl │ └── debian │ │ ├── changelog │ │ ├── compat │ │ ├── control │ │ ├── copyright │ │ ├── kubectl.install │ │ ├── postinst │ │ ├── rules │ │ └── source │ │ └── format └── kubelet │ ├── debian │ ├── changelog │ ├── compat │ ├── control │ ├── copyright │ ├── kubelet.install │ ├── postinst │ ├── rules │ └── source │ │ └── format │ └── lib │ └── systemd │ └── system │ └── kubelet.service ├── hack ├── build_binaries.sh ├── build_image.sh ├── checkout.sh ├── format_all_patch.sh ├── format_patch.sh ├── gen_verify_workflows.sh ├── git_sync_repos.sh ├── image_manifest_push.sh ├── image_manifest_retags.sh ├── image_other.sh ├── image_tag.sh ├── install_etcd.sh ├── kit.sh ├── pkg_deb.sh ├── pkg_rpm.sh ├── public_source.sh ├── test.sh ├── test_cmd.sh ├── test_e2e.sh ├── test_e2e_node.sh ├── test_integration.sh ├── verify_build.sh ├── verify_build_client.sh ├── verify_build_image.sh ├── verify_build_server.sh ├── verify_patch.sh ├── verify_patch_format.sh ├── verify_pkg_deb_client.sh ├── verify_pkg_deb_server.sh ├── verify_pkg_rpm_client.sh ├── verify_pkg_rpm_server.sh └── verify_releases.sh ├── patches ├── CVE-2019-1002100.1.10.patch ├── CVE-2019-1002101.1.10.patch ├── CVE-2019-11246.1.10.patch ├── CVE-2019-11246.1.11.patch ├── CVE-2019-11247.1.11.patch ├── CVE-2019-11248.1.11.patch ├── CVE-2019-11249.1.10.patch ├── CVE-2019-11249.1.12.patch ├── CVE-2019-11251.1.10.patch ├── CVE-2020-8552.1.11.patch ├── CVE-2020-8552.1.13.patch ├── CVE-2020-8552.1.14.patch ├── CVE-2020-8554.1.18.patch ├── CVE-2020-8554.1.19.patch ├── CVE-2020-8555.1.14.patch ├── CVE-2020-8558.1.12.patch ├── CVE-2020-8559.1.12.patch ├── CVE-2020-8559.1.13.patch ├── CVE-2021-25741.1.18.patch ├── codegens-to-scripts.1.24.patch ├── codegens-to-scripts.1.25.patch ├── fix-etcd-health.1.11.patch ├── fix-etcd-health.1.16.patch ├── fix-etcd-put-key.1.11.patch ├── fix-etcd-put-key.1.23.patch ├── fix-etcd-put-key.1.24.patch ├── fix-image-name.1.12.patch ├── fix-kubectl-convert-97644.1.20.patch ├── fix-missing-env-91500.1.18.patch ├── fix-run-docker.1.24.patch ├── fix-test.1.16.patch ├── no-delete-images.1.10.patch ├── no-delete-images.1.12.patch ├── no-delete-images.1.15.patch ├── no-delete-images.1.24.patch ├── nokmem.1.13.patch ├── nokmem.1.20.patch └── update-kube-proxy-iptables.1.18.patch ├── releases.yml └── rpm ├── kubeadm ├── 10-kubeadm.conf └── kubeadm.spec ├── kubectl └── kubectl.spec └── kubelet ├── kubelet.env ├── kubelet.service └── kubelet.spec /.github/ISSUE_TEMPLATE/bug-report.yaml: -------------------------------------------------------------------------------- 1 | name: Bug Report 2 | description: Report a bug encountered while operating Kubernetes 3 | labels: 4 | - kind/bug 5 | body: 6 | - type: textarea 7 | id: problem 8 | attributes: 9 | label: What happened? 10 | description: Please provide as much info as possible. 11 | validations: 12 | required: true 13 | 14 | - type: textarea 15 | id: expected 16 | attributes: 17 | label: What did you expect to happen? 18 | validations: 19 | required: true 20 | 21 | - type: textarea 22 | id: reproduce 23 | attributes: 24 | label: How can we reproduce it (as minimally and precisely as possible)? 25 | validations: 26 | required: true 27 | 28 | - type: textarea 29 | id: additional 30 | attributes: 31 | label: Anything else we need to know? 32 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/enhancement.yaml: -------------------------------------------------------------------------------- 1 | name: Enhancement Tracking Issue 2 | description: Provide supporting details for a feature in development 3 | labels: 4 | - kind/feature 5 | body: 6 | - type: textarea 7 | id: feature 8 | attributes: 9 | label: What would you like to be added? 10 | description: Feature requests are unlikely to make progress as issues. 11 | validations: 12 | required: true 13 | 14 | - type: textarea 15 | id: rationale 16 | attributes: 17 | label: Why is this needed? 18 | validations: 19 | required: true 20 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | #### What type of PR is this? 2 | 3 | 10 | 11 | #### What this PR does / why we need it: 12 | 13 | #### Which issue(s) this PR fixes: 14 | 18 | Fixes # 19 | 20 | #### Special notes for your reviewer: 21 | 22 | #### Does this PR introduce a user-facing change? 23 | 28 | ```release-note 29 | 30 | ``` 31 | -------------------------------------------------------------------------------- /.github/workflows/ci-bot.yml: -------------------------------------------------------------------------------- 1 | name: CI Bot 2 | on: 3 | issue_comment: 4 | types: 5 | - created 6 | pull_request_review_comment: 7 | types: 8 | - created 9 | issues: 10 | types: 11 | - opened 12 | pull_request: 13 | types: 14 | - opened 15 | 16 | env: 17 | # This plugins is for anyone who can use it 18 | PLUGINS: |- 19 | assign 20 | auto-cc 21 | cc 22 | label-kind 23 | label-bug 24 | label-documentation 25 | label-enhancement 26 | label-question 27 | 28 | # This plugins is for organization member or repository member 29 | MEMBERS_PLUGINS: |- 30 | label-duplicate 31 | label-good-first-issue 32 | label-help-wanted 33 | label-invalid 34 | label-kind 35 | label-wontfix 36 | lifecycle 37 | 38 | # This plugins is for in the REVIEWERS environment variable 39 | REVIEWERS_PLUGINS: |- 40 | retitle 41 | # This plugins is for in the APPROVERS environment variable 42 | APPROVERS_PLUGINS: |- 43 | merge 44 | # This plugins is for in the MAINTAINERS environment variable 45 | MAINTAINERS_PLUGINS: |- 46 | milestone 47 | # This plugins is for organization owner or repository owner 48 | OWNERS_PLUGINS: "" 49 | 50 | REVIEWERS: |- 51 | pacoxu 52 | wzshiming 53 | APPROVERS: |- 54 | pacoxu 55 | wzshiming 56 | MAINTAINERS: |- 57 | pacoxu 58 | wzshiming 59 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 60 | GH_REPOSITORY: ${{ github.repository }} 61 | DETAILS: |- 62 |
63 | Details 64 | Instructions for interacting with me using comments are available here. 65 | If you have questions or suggestions related to my behavior, please file an issue against the [gh-ci-bot](https://github.com/wzshiming/gh-ci-bot) repository. 66 |
67 | jobs: 68 | 69 | issue_opened: 70 | name: Issue Opened 71 | if: ${{ github.event_name == 'issues' }} 72 | runs-on: ubuntu-latest 73 | steps: 74 | - uses: wzshiming/gh-ci-bot@v1 75 | env: 76 | LOGIN: ${{ github.event.issue.user.login }} 77 | MESSAGE: ${{ github.event.issue.body }} 78 | ISSUE_NUMBER: ${{ github.event.issue.number }} 79 | AUTHOR_ASSOCIATION: ${{ github.event.issue.author_association }} 80 | ISSUE_KIND: issue 81 | TYPE: created 82 | GREETING: |- 83 | Hi @${{ github.event.issue.user.login }}, 84 | Thanks for opening an issue! 85 | We will look into it as soon as possible. 86 | pr_opened: 87 | name: PR Opened 88 | if: ${{ github.event_name == 'pull_request' }} 89 | runs-on: ubuntu-latest 90 | steps: 91 | - uses: wzshiming/gh-ci-bot@v1 92 | env: 93 | LOGIN: ${{ github.event.pull_request.user.login }} 94 | MESSAGE: ${{ github.event.pull_request.body }} 95 | ISSUE_NUMBER: ${{ github.event.pull_request.number }} 96 | AUTHOR_ASSOCIATION: ${{ github.event.pull_request.author_association }} 97 | ISSUE_KIND: pr 98 | TYPE: created 99 | GREETING: |- 100 | Hi @${{ github.event.pull_request.user.login }}, 101 | Thanks for your pull request! 102 | If the PR is ready, use the `/auto-cc` command to assign Reviewer to Review. 103 | We will review it shortly. 104 | issue_commented: 105 | name: Issue Commented 106 | if: ${{ github.event_name == 'issue_comment' && !github.event.issue.pull_request }} 107 | runs-on: ubuntu-latest 108 | steps: 109 | - uses: wzshiming/gh-ci-bot@v1 110 | env: 111 | LOGIN: ${{ github.event.comment.user.login }} 112 | MESSAGE: ${{ github.event.comment.body }} 113 | ISSUE_NUMBER: ${{ github.event.issue.number }} 114 | AUTHOR_ASSOCIATION: ${{ github.event.comment.author_association }} 115 | ISSUE_KIND: issue 116 | TYPE: comment 117 | 118 | pr_review_commented: 119 | name: PR Review Commented 120 | if: ${{ github.event_name == 'pull_request_review_comment' }} 121 | runs-on: ubuntu-latest 122 | steps: 123 | - uses: wzshiming/gh-ci-bot@v1 124 | env: 125 | LOGIN: ${{ github.event.comment.user.login }} 126 | MESSAGE: ${{ github.event.comment.body }} 127 | ISSUE_NUMBER: ${{ github.event.pull_request.number }} 128 | AUTHOR_ASSOCIATION: ${{ github.event.comment.author_association }} 129 | ISSUE_KIND: pr 130 | TYPE: comment 131 | 132 | pr_commented: 133 | name: PR Commented 134 | if: ${{ github.event_name == 'issue_comment' && github.event.issue.pull_request }} 135 | runs-on: ubuntu-latest 136 | steps: 137 | - uses: wzshiming/gh-ci-bot@v1 138 | env: 139 | LOGIN: ${{ github.event.comment.user.login }} 140 | MESSAGE: ${{ github.event.comment.body }} 141 | ISSUE_NUMBER: ${{ github.event.issue.number }} 142 | AUTHOR_ASSOCIATION: ${{ github.event.comment.author_association }} 143 | ISSUE_KIND: pr 144 | TYPE: comment 145 | -------------------------------------------------------------------------------- /.github/workflows/releases-images.yml: -------------------------------------------------------------------------------- 1 | name: Releases Images 2 | 3 | on: 4 | push: 5 | tags: 6 | - v* 7 | 8 | workflow_dispatch: 9 | 10 | jobs: 11 | Images: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v2 15 | - name: Install dependent 16 | run: | 17 | make dependent 18 | - name: Config Github 19 | run: | 20 | git config --global user.email "noreply@github.com" 21 | git config --global user.name "GitHub" 22 | - name: Checkout 23 | run: | 24 | make $(basename ${GITHUB_REF}) 25 | - name: Build images 26 | run: | 27 | make build-image 28 | - name: Login registry 29 | run: | 30 | echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin 31 | - name: Push images 32 | run: | 33 | OLD_REGISTRY=registry.k8s.io REGISTRY="ghcr.io/$(echo ${{ github.repository }} | tr "A-Z" "a-z")" make push-image 34 | - name: Sync others image 35 | env: 36 | GH_ID: ${{ github.actor }} 37 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 38 | run: | 39 | sudo mkdir -p /run/containers && sudo chmod 777 /run/containers 40 | skopeo login -u ${GH_ID} -p ${GH_TOKEN} ghcr.io 41 | REGISTRY="ghcr.io/$(echo ${{ github.repository }} | tr "A-Z" "a-z")" make image-other 42 | -------------------------------------------------------------------------------- /.github/workflows/releases-package.yml: -------------------------------------------------------------------------------- 1 | name: Releases Packages 2 | 3 | on: 4 | push: 5 | tags: 6 | - v* 7 | 8 | workflow_dispatch: 9 | 10 | jobs: 11 | Build: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v2 15 | - name: Install dependent 16 | run: | 17 | make dependent 18 | - name: Config Github 19 | run: | 20 | git config --global user.email "noreply@github.com" 21 | git config --global user.name "GitHub" 22 | - name: Checkout 23 | run: | 24 | make $(basename ${GITHUB_REF}) 25 | - name: Build binaries 26 | run: | 27 | make build-binaries 28 | 29 | - name: Package rpm 30 | run: | 31 | make pkg-rpm 32 | - name: Sync repository 33 | env: 34 | BRANCH_PREFIX: "rpm-" 35 | REPOS: "rpm" 36 | run: | 37 | GH_TOKEN="${GH_TOKEN:-${{ secrets.GITHUB_TOKEN }}}" SOURCE="${SOURCE:-https://github.com/${{ github.repository }}}" make repos-sync 38 | 39 | - name: Package deb 40 | run: | 41 | make pkg-deb 42 | - name: Sync repository 43 | env: 44 | BRANCH_PREFIX: "deb-" 45 | REPOS: "deb" 46 | run: | 47 | GH_TOKEN="${GH_TOKEN:-${{ secrets.GITHUB_TOKEN }}}" SOURCE="${SOURCE:-https://github.com/${{ github.repository }}}" make repos-sync 48 | -------------------------------------------------------------------------------- /.github/workflows/releases-source.yml: -------------------------------------------------------------------------------- 1 | name: Releases Source 2 | 3 | on: 4 | push: 5 | tags: 6 | - v* 7 | 8 | workflow_dispatch: 9 | 10 | jobs: 11 | Build: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v2 15 | - name: Install dependent 16 | run: | 17 | make dependent 18 | - name: Config Github 19 | run: | 20 | git config --global user.email "noreply@github.com" 21 | git config --global user.name "GitHub" 22 | - name: Checkout 23 | run: | 24 | make $(basename ${GITHUB_REF}) 25 | - name: Release source 26 | env: 27 | SOURCE: https://github.com/klts-io/kubernetes 28 | GH_TOKEN: ${{ secrets.GH_TOKEN }} 29 | run: | 30 | make public-source 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | kit/ 2 | src/ 3 | output/ 4 | release/ 5 | rpmbuild/ 6 | debbuild/ 7 | repos/ 8 | tmp/ 9 | .* 10 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | v%: 3 | @echo Checkout to $@ 4 | ./hack/checkout.sh $@ 5 | 6 | dependent: 7 | pip3 install yq 8 | ./hack/kit.sh 9 | 10 | .PHONY: public-source 11 | public-source: 12 | @echo Public Source 13 | ./hack/public_source.sh 14 | 15 | .PHONY: build-binaries 16 | build-binaries: 17 | @echo Build binaries 18 | ./hack/build_binaries.sh 19 | 20 | .PHONY: pkg-rpm 21 | pkg-rpm: 22 | ./hack/pkg_rpm.sh 23 | 24 | .PHONY: pkg-deb 25 | pkg-deb: 26 | ./hack/pkg_deb.sh 27 | 28 | .PHONY: repos-sync 29 | repos-sync: 30 | ./hack/git_sync_repos.sh 31 | 32 | .PHONY: build-image 33 | build-image: 34 | @echo Build image 35 | ./hack/build_image.sh 36 | 37 | .PHONY: image-other 38 | image-other: 39 | ./hack/image_other.sh 40 | 41 | .PHONY: verify 42 | verify: verify-patch 43 | 44 | .PHONY: verify-patch 45 | verify-patch: 46 | ./hack/verify_patch.sh 47 | 48 | .PHONY: verify-releases 49 | verify-releases: 50 | ./hack/verify_releases.sh 51 | 52 | .PHONY: verify-patch-format 53 | verify-patch-format: 54 | ./hack/verify_patch_format.sh 55 | 56 | .PHONY: verify-build 57 | verify-build: 58 | ./hack/verify_build.sh 59 | 60 | .PHONY: verify-build-client 61 | verify-build-client: 62 | ./hack/verify_build_client.sh 63 | 64 | .PHONY: verify-build-server 65 | verify-build-server: 66 | ./hack/verify_build_server.sh 67 | 68 | .PHONY: verify-pkg-rpm-client 69 | verify-pkg-rpm-client: 70 | ./hack/verify_pkg_rpm_client.sh 71 | 72 | .PHONY: verify-pkg-rpm-server 73 | verify-pkg-rpm-server: 74 | ./hack/verify_pkg_rpm_server.sh 75 | 76 | .PHONY: verify-pkg-deb-client 77 | verify-pkg-deb-client: 78 | ./hack/verify_pkg_deb_client.sh 79 | 80 | .PHONY: verify-pkg-deb-server 81 | verify-pkg-deb-server: 82 | ./hack/verify_pkg_deb_server.sh 83 | 84 | .PHONY: verify-build-image 85 | verify-build-image: 86 | ./hack/verify_build_image.sh 87 | 88 | .PHONY: gen-verify-workflows 89 | gen-verify-workflows: 90 | ./hack/gen_verify_workflows.sh > .github/workflows/verify.yml 91 | 92 | .PHONY: push-image 93 | push-image: 94 | ./hack/image_tag.sh && ./hack/image_manifest_push.sh 95 | 96 | .PHONY: format-all-patch 97 | format-all-patch: 98 | ./hack/format_all_patch.sh 99 | 100 | .PHONY: test 101 | test: 102 | ./hack/test.sh 103 | 104 | .PHONY: test-cmd 105 | test-cmd: 106 | ./hack/test_cmd.sh 107 | 108 | .PHONY: test-integration 109 | test-integration: 110 | ./hack/test_integration.sh 111 | 112 | .PHONY: test-e2e 113 | test-e2e: 114 | ./hack/test_e2e.sh 115 | 116 | .PHONY: test-e2e-node 117 | test-e2e-node: 118 | ./hack/test_e2e_node.sh 119 | 120 | .PHONY: install-etcd 121 | install-etcd: 122 | ./hack/install_etcd.sh 123 | -------------------------------------------------------------------------------- /OWNERS: -------------------------------------------------------------------------------- 1 | # See the OWNERS docs at https://go.klts.io/owners 2 | 3 | approvers: 4 | - wzshiming 5 | - kerthcet 6 | - calvin0327 7 | reviewers: 8 | - mengjiao-liu 9 | - pacoxu 10 | - Ericwvi 11 | - jonyhy96 12 | - cyclinder 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # KLTS 4 | KLTS, known as Kubernetes Long Term Support, provides free maintenance support for early Kubernetes versions for up to three years, actively fix the CVE vulnerabilities and critical bugs, to help many enterprise users to stay with early Kubernetes versions. 5 | 6 | ---- 7 | 8 | ## To start using KLTS 9 | 10 | ### Available KLTS Versions 11 | Below lists the status of each release image and package and you can click any to learn the detailed logs. 12 | | |Images|Packages| 13 | |-|-|-| 14 | |v1.28.15|[![v1.28.15-lts.0](https://github.com/klts-io/kubernetes-lts/actions/workflows/releases-images.yml/badge.svg?branch=v1.28.15-lts.0)](https://klts.io/docs/kubernetes/releases/v1.28/v1.28.15-lts.0/)|[![v1.28.15-lts.0](https://github.com/klts-io/kubernetes-lts/actions/workflows/releases-package.yml/badge.svg?branch=v1.28.15-lts.0)](https://klts.io/docs/kubernetes/releases/v1.28/v1.28.15-lts.0/)| 15 | |v1.27.16|[![v1.27.16-lts.0](https://github.com/klts-io/kubernetes-lts/actions/workflows/releases-images.yml/badge.svg?branch=v1.27.16-lts.0)](https://klts.io/docs/kubernetes/releases/v1.27/v1.27.16-lts.0/)|[![v1.27.16-lts.0](https://github.com/klts-io/kubernetes-lts/actions/workflows/releases-package.yml/badge.svg?branch=v1.27.16-lts.0)](https://klts.io/docs/kubernetes/releases/v1.27/v1.27.16-lts.0/)| 16 | |v1.26.15|[![v1.26.15-lts.0](https://github.com/klts-io/kubernetes-lts/actions/workflows/releases-images.yml/badge.svg?branch=v1.26.15-lts.0)](https://klts.io/docs/kubernetes/releases/v1.26/v1.26.15-lts.0/)|[![v1.26.15-lts.0](https://github.com/klts-io/kubernetes-lts/actions/workflows/releases-package.yml/badge.svg?branch=v1.26.15-lts.0)](https://klts.io/docs/kubernetes/releases/v1.26/v1.26.15-lts.0/)| 17 | |v1.25.16|[![v1.25.16-lts.0](https://github.com/klts-io/kubernetes-lts/actions/workflows/releases-images.yml/badge.svg?branch=v1.25.16-lts.0)](https://klts.io/docs/kubernetes/releases/v1.25/v1.25.16-lts.0/)|[![v1.25.16-lts.0](https://github.com/klts-io/kubernetes-lts/actions/workflows/releases-package.yml/badge.svg?branch=v1.25.16-lts.0)](https://klts.io/docs/kubernetes/releases/v1.25/v1.25.16-lts.0/)| 18 | |v1.24.17|[![v1.24.17-lts.0](https://github.com/klts-io/kubernetes-lts/actions/workflows/releases-images.yml/badge.svg?branch=v1.24.17-lts.0)](https://klts.io/docs/kubernetes/releases/v1.24/v1.24.17-lts.0/)|[![v1.24.17-lts.0](https://github.com/klts-io/kubernetes-lts/actions/workflows/releases-package.yml/badge.svg?branch=v1.24.17-lts.0)](https://klts.io/docs/kubernetes/releases/v1.24/v1.24.17-lts.0/)| 19 | |v1.23.17|[![v1.23.17-lts.0](https://github.com/klts-io/kubernetes-lts/actions/workflows/releases-images.yml/badge.svg?branch=v1.23.17-lts.0)](https://klts.io/docs/kubernetes/releases/v1.23/v1.23.17-lts.0/)|[![v1.23.17-lts.0](https://github.com/klts-io/kubernetes-lts/actions/workflows/releases-package.yml/badge.svg?branch=v1.23.17-lts.0)](https://klts.io/docs/kubernetes/releases/v1.23/v1.23.17-lts.0/)| 20 | |v1.22.17|[![v1.22.17-lts.0](https://github.com/klts-io/kubernetes-lts/actions/workflows/releases-images.yml/badge.svg?branch=v1.22.17-lts.0)](https://klts.io/docs/kubernetes/releases/v1.22/v1.22.17-lts.0/)|[![v1.22.17-lts.0](https://github.com/klts-io/kubernetes-lts/actions/workflows/releases-package.yml/badge.svg?branch=v1.22.17-lts.0)](https://klts.io/docs/kubernetes/releases/v1.22/v1.22.17-lts.0/)| 21 | |v1.21.14|[![v1.21.14-lts.1](https://github.com/klts-io/kubernetes-lts/actions/workflows/releases-images.yml/badge.svg?branch=v1.21.14-lts.1)](https://klts.io/docs/kubernetes/releases/v1.21/v1.21.14-lts.1/)|[![v1.21.14-lts.1](https://github.com/klts-io/kubernetes-lts/actions/workflows/releases-package.yml/badge.svg?branch=v1.21.14-lts.1)](https://klts.io/docs/kubernetes/releases/v1.21/v1.21.14-lts.1/)| 22 | |v1.20.15|[![v1.20.15-lts.2](https://github.com/klts-io/kubernetes-lts/actions/workflows/releases-images.yml/badge.svg?branch=v1.20.15-lts.2)](https://klts.io/docs/kubernetes/releases/v1.20/v1.20.15-lts.2/)|[![v1.20.15-lts.2](https://github.com/klts-io/kubernetes-lts/actions/workflows/releases-package.yml/badge.svg?branch=v1.20.15-lts.2)](https://klts.io/docs/kubernetes/releases/v1.20/v1.20.15-lts.2/)| 23 | |v1.19.16|[![v1.19.16-lts.3](https://github.com/klts-io/kubernetes-lts/actions/workflows/releases-images.yml/badge.svg?branch=v1.19.16-lts.3)](https://klts.io/docs/kubernetes/releases/v1.19/v1.19.16-lts.3/)|[![v1.19.16-lts.3](https://github.com/klts-io/kubernetes-lts/actions/workflows/releases-package.yml/badge.svg?branch=v1.19.16-lts.3)](https://klts.io/docs/kubernetes/releases/v1.19/v1.19.16-lts.3/)| 24 | |v1.18.20|[![v1.18.20-lts.2](https://github.com/klts-io/kubernetes-lts/actions/workflows/releases-images.yml/badge.svg?branch=v1.18.20-lts.2)](https://klts.io/docs/kubernetes/releases/v1.18/v1.18.20-lts.2/)|[![v1.18.20-lts.2](https://github.com/klts-io/kubernetes-lts/actions/workflows/releases-package.yml/badge.svg?branch=v1.18.20-lts.2)](https://klts.io/docs/kubernetes/releases/v1.18/v1.18.20-lts.2/)| 25 | |v1.17.17|[![v1.17.17-lts.1](https://github.com/klts-io/kubernetes-lts/actions/workflows/releases-images.yml/badge.svg?branch=v1.17.17-lts.1)](https://klts.io/docs/kubernetes/releases/v1.17/v1.17.17-lts.1/)|[![v1.17.17-lts.1](https://github.com/klts-io/kubernetes-lts/actions/workflows/releases-package.yml/badge.svg?branch=v1.17.17-lts.1)](https://klts.io/docs/kubernetes/releases/v1.17/v1.17.17-lts.1/)| 26 | |v1.16.15|[![v1.16.15-lts.1](https://github.com/klts-io/kubernetes-lts/actions/workflows/releases-images.yml/badge.svg?branch=v1.16.15-lts.1)](https://klts.io/docs/kubernetes/releases/v1.16/v1.16.15-lts.1/)|[![v1.16.15-lts.1](https://github.com/klts-io/kubernetes-lts/actions/workflows/releases-package.yml/badge.svg?branch=v1.16.15-lts.1)](https://klts.io/docs/kubernetes/releases/v1.16/v1.16.15-lts.1/)| 27 | |v1.15.12|[![v1.15.12-lts.1](https://github.com/klts-io/kubernetes-lts/actions/workflows/releases-images.yml/badge.svg?branch=v1.15.12-lts.1)](https://klts.io/docs/kubernetes/releases/v1.15/v1.15.12-lts.1/)|[![v1.15.12-lts.1](https://github.com/klts-io/kubernetes-lts/actions/workflows/releases-package.yml/badge.svg?branch=v1.15.12-lts.1)](https://klts.io/docs/kubernetes/releases/v1.15/v1.15.12-lts.1/)| 28 | |v1.14.10|[![v1.14.10-lts.1](https://github.com/klts-io/kubernetes-lts/actions/workflows/releases-images.yml/badge.svg?branch=v1.14.10-lts.1)](https://klts.io/docs/kubernetes/releases/v1.14/v1.14.10-lts.1/)|[![v1.14.10-lts.1](https://github.com/klts-io/kubernetes-lts/actions/workflows/releases-package.yml/badge.svg?branch=v1.14.10-lts.1)](https://klts.io/docs/kubernetes/releases/v1.14/v1.14.10-lts.1/)| 29 | |v1.13.12|[![v1.13.12-lts.1](https://github.com/klts-io/kubernetes-lts/actions/workflows/releases-images.yml/badge.svg?branch=v1.13.12-lts.1)](https://klts.io/docs/kubernetes/releases/v1.13/v1.13.12-lts.1/)|[![v1.13.12-lts.1](https://github.com/klts-io/kubernetes-lts/actions/workflows/releases-package.yml/badge.svg?branch=v1.13.12-lts.1)](https://klts.io/docs/kubernetes/releases/v1.13/v1.13.12-lts.1/)| 30 | |v1.12.10|[![v1.12.10-lts.1](https://github.com/klts-io/kubernetes-lts/actions/workflows/releases-images.yml/badge.svg?branch=v1.12.10-lts.1)](https://klts.io/docs/kubernetes/releases/v1.12/v1.12.10-lts.1/)|[![v1.12.10-lts.1](https://github.com/klts-io/kubernetes-lts/actions/workflows/releases-package.yml/badge.svg?branch=v1.12.10-lts.1)](https://klts.io/docs/kubernetes/releases/v1.12/v1.12.10-lts.1/)| 31 | |v1.11.10|[![v1.11.10-lts.1](https://github.com/klts-io/kubernetes-lts/actions/workflows/releases-images.yml/badge.svg?branch=v1.11.10-lts.1)](https://klts.io/docs/kubernetes/releases/v1.11/v1.11.10-lts.1/)|[![v1.11.10-lts.1](https://github.com/klts-io/kubernetes-lts/actions/workflows/releases-package.yml/badge.svg?branch=v1.11.10-lts.1)](https://klts.io/docs/kubernetes/releases/v1.11/v1.11.10-lts.1/)| 32 | |v1.10.13|[![v1.10.13-lts.1](https://github.com/klts-io/kubernetes-lts/actions/workflows/releases-images.yml/badge.svg?branch=v1.10.13-lts.1)](https://klts.io/docs/kubernetes/releases/v1.10/v1.10.13-lts.1/)|[![v1.10.13-lts.1](https://github.com/klts-io/kubernetes-lts/actions/workflows/releases-package.yml/badge.svg?branch=v1.10.13-lts.1)](https://klts.io/docs/kubernetes/releases/v1.10/v1.10.13-lts.1/)| 33 | 34 | ### CVE Source 35 | 36 | - [CVEs that were cherry-pick approved and merged after pull requests](https://github.com/kubernetes/kubernetes/pulls?q=is%3Apr+is%3Amerged+label%3Acherry-pick-approved+CVE) 37 | 38 | - [CVEs that were found and fixed recently](https://www.cvedetails.com/vulnerability-list/vendor_id-15867/product_id-34016/Kubernetes-Kubernetes.html) 39 | 40 | - [Kubernetes-related CVEs that were found and listed on cve.org recently](https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=Kubernetes) 41 | 42 | 43 | 44 | ### Documents 45 | 46 | - [Portal and Docs](https://klts.io/docs/) 47 | - [Install Guide](https://klts.io/docs/install/) 48 | 49 | 50 | ----------------------- 51 | 52 | ## To start contributing KLTS 53 | 54 | ### Check out the specified patch release 55 | 56 | You can directly check out the specified release by running the following code. For details about the releases provided by KLTS, see [./releases.yml](https://github.com/klts-io/kubernetes-lts/blob/master/releases.yml) 57 | 58 | ``` bash 59 | make v1.19.16-lts.3 60 | ``` 61 | 62 | ### Build 63 | 64 | Since the repos branch is used as a software source for RPM and DEB and direct cloning is very large, you can try to only clone a single branch as follows. 65 | 66 | ``` bash 67 | git clone --single-branch -b main https://github.com/klts-io/kubernetes-lts 68 | ``` 69 | 70 | #### Build image 71 | Run the following code to build your image: 72 | 73 | ``` bash 74 | make build-image 75 | ``` 76 | 77 | Check more images from [Images artifacts](https://github.com/orgs/klts-io/packages?repo_name=kubernetes-lts). 78 | 79 | #### Build client and server 80 | Run the following code to build the client and server: 81 | 82 | ``` bash 83 | make build-binaries 84 | ``` 85 | #### Official patch release 86 | For details about Kubernetes patch releases, see [patch release](https://kubernetes.io/releases/patch-releases/). 87 | 88 | ## Contributors 89 | 90 | 91 | 92 | 93 | 94 | Made with [contrib.rocks](https://contrib.rocks). 95 | 96 | ## License 97 | Copyright 2022 the KLTS.io Authors. All rights reserved. 98 | 99 | Licensed under the Apache License, Version 2.0. 100 | -------------------------------------------------------------------------------- /deb/kubeadm/debian/changelog: -------------------------------------------------------------------------------- 1 | kubeadm (%{_version}-%{_release}) lts; urgency=medium 2 | 3 | * https://git.k8s.io/kubernetes/CHANGELOG/README.md 4 | -------------------------------------------------------------------------------- /deb/kubeadm/debian/compat: -------------------------------------------------------------------------------- 1 | 9 2 | -------------------------------------------------------------------------------- /deb/kubeadm/debian/control: -------------------------------------------------------------------------------- 1 | Source: kubeadm 2 | Section: misc 3 | Priority: optional 4 | Maintainer: Kubernetes Authors 5 | Build-Depends: ca-certificates, debhelper (>= 8.0.0) 6 | Standards-Version: 3.9.4 7 | Homepage: https://kubernetes.io 8 | Vcs-Git: https://github.com/kubernetes/kubernetes.git 9 | Vcs-Browser: https://github.com/kubernetes/kubernetes 10 | 11 | Package: kubeadm 12 | Architecture: %{_arch} 13 | Depends: kubelet (>= 1.10.0), kubectl (>= 1.10.0), kubernetes-cni (>= 0.8.6), cri-tools (>= 1.13.0), ${misc:Depends} 14 | Description: Kubernetes Cluster Bootstrapping Tool 15 | The Kubernetes command line tool for bootstrapping a Kubernetes cluster. 16 | -------------------------------------------------------------------------------- /deb/kubeadm/debian/copyright: -------------------------------------------------------------------------------- 1 | Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ 2 | Upstream-Name: kubeadm 3 | Source: https://github.com/kubernetes/kubernetes 4 | 5 | Files: * 6 | Copyright: 2016 The Kubernetes Authors. 7 | License: Apache-2.0 8 | Licensed under the Apache License, Version 2.0 (the "License"); 9 | you may not use this file except in compliance with the License. 10 | You may obtain a copy of the License at 11 | . 12 | http://www.apache.org/licenses/LICENSE-2.0 13 | . 14 | Unless required by applicable law or agreed to in writing, software 15 | distributed under the License is distributed on an "AS IS" BASIS, 16 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | See the License for the specific language governing permissions and 18 | limitations under the License. 19 | -------------------------------------------------------------------------------- /deb/kubeadm/debian/kubeadm.install: -------------------------------------------------------------------------------- 1 | usr/bin/kubeadm usr/bin/ 2 | etc/systemd/system/kubelet.service.d/10-kubeadm.conf etc/systemd/system/kubelet.service.d/ 3 | -------------------------------------------------------------------------------- /deb/kubeadm/debian/postinst: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # see: dh_installdeb(1) 3 | 4 | set -o errexit 5 | set -o nounset 6 | 7 | # summary of how this script can be called: 8 | # * `configure' 9 | # * `abort-upgrade' 10 | # * `abort-remove' `in-favour' 11 | # 12 | # * `abort-remove' 13 | # * `abort-deconfigure' `in-favour' 14 | # `removing' 15 | # 16 | # for details, see https://www.debian.org/doc/debian-policy/ or 17 | # the debian-policy package 18 | 19 | 20 | case "$1" in 21 | configure) 22 | # because kubeadm package adds kubelet drop-ins, we must daemon-reload 23 | # and restart kubelet now. restarting kubelet is ok because kubelet 24 | # postinst configure step auto-starts it. 25 | systemctl daemon-reload 2>/dev/null || true 26 | systemctl restart kubelet 2>/dev/null || true 27 | ;; 28 | 29 | abort-upgrade|abort-remove|abort-deconfigure) 30 | ;; 31 | 32 | *) 33 | echo "postinst called with unknown argument \`$1'" >&2 34 | exit 1 35 | ;; 36 | esac 37 | 38 | # dh_installdeb will replace this with shell code automatically 39 | # generated by other debhelper scripts. 40 | 41 | #DEBHELPER# 42 | 43 | exit 0 44 | -------------------------------------------------------------------------------- /deb/kubeadm/debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | # -*- makefile -*- 3 | 4 | #export DH_VERBOSE=1 5 | KUBE_LOCAL_ARTIFACTS?= 6 | 7 | build: 8 | echo noop 9 | 10 | binary: 11 | mkdir -p usr/bin 12 | cp kubeadm usr/bin/kubeadm 13 | chmod +x usr/bin/kubeadm 14 | dh_testroot 15 | dh_auto_install 16 | dh_shlibdeps 17 | dh_install 18 | dh_installdeb 19 | dh_gencontrol 20 | dh_md5sums 21 | dh_builddeb 22 | 23 | %: 24 | dh $@ 25 | -------------------------------------------------------------------------------- /deb/kubeadm/debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (native) 2 | -------------------------------------------------------------------------------- /deb/kubeadm/etc/systemd/system/kubelet.service.d/10-kubeadm.conf: -------------------------------------------------------------------------------- 1 | # Note: This dropin only works with kubeadm and kubelet v1.11+ 2 | [Service] 3 | Environment="KUBELET_KUBECONFIG_ARGS=--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf" 4 | Environment="KUBELET_CONFIG_ARGS=--config=/var/lib/kubelet/config.yaml" 5 | # This is a file that "kubeadm init" and "kubeadm join" generates at runtime, populating the KUBELET_KUBEADM_ARGS variable dynamically 6 | EnvironmentFile=-/var/lib/kubelet/kubeadm-flags.env 7 | # This is a file that the user can use for overrides of the kubelet args as a last resort. Preferably, the user should use 8 | # the .NodeRegistration.KubeletExtraArgs object in the configuration files instead. KUBELET_EXTRA_ARGS should be sourced from this file. 9 | EnvironmentFile=-/etc/default/kubelet 10 | ExecStart= 11 | ExecStart=/usr/bin/kubelet $KUBELET_KUBECONFIG_ARGS $KUBELET_CONFIG_ARGS $KUBELET_KUBEADM_ARGS $KUBELET_EXTRA_ARGS 12 | -------------------------------------------------------------------------------- /deb/kubectl/debian/changelog: -------------------------------------------------------------------------------- 1 | kubectl (%{_version}-%{_release}) lts; urgency=medium 2 | 3 | * https://git.k8s.io/kubernetes/CHANGELOG/README.md 4 | -------------------------------------------------------------------------------- /deb/kubectl/debian/compat: -------------------------------------------------------------------------------- 1 | 9 2 | -------------------------------------------------------------------------------- /deb/kubectl/debian/control: -------------------------------------------------------------------------------- 1 | Source: kubectl 2 | Section: misc 3 | Priority: optional 4 | Maintainer: Kubernetes Authors 5 | Build-Depends: ca-certificates, debhelper (>= 8.0.0) 6 | Standards-Version: 3.9.4 7 | Homepage: https://kubernetes.io 8 | Vcs-Git: https://github.com/kubernetes/kubernetes.git 9 | Vcs-Browser: https://github.com/kubernetes/kubernetes 10 | 11 | Package: kubectl 12 | Architecture: %{_arch} 13 | Depends: ${misc:Depends} 14 | Description: Kubernetes Command Line Tool 15 | The Kubernetes command line tool for interacting with the Kubernetes API. 16 | -------------------------------------------------------------------------------- /deb/kubectl/debian/copyright: -------------------------------------------------------------------------------- 1 | Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ 2 | Upstream-Name: kubectl 3 | Source: https://github.com/kubernetes/kubernetes 4 | 5 | Files: * 6 | Copyright: 2016 The Kubernetes Authors. 7 | License: Apache-2.0 8 | Licensed under the Apache License, Version 2.0 (the "License"); 9 | you may not use this file except in compliance with the License. 10 | You may obtain a copy of the License at 11 | . 12 | http://www.apache.org/licenses/LICENSE-2.0 13 | . 14 | Unless required by applicable law or agreed to in writing, software 15 | distributed under the License is distributed on an "AS IS" BASIS, 16 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | See the License for the specific language governing permissions and 18 | limitations under the License. 19 | -------------------------------------------------------------------------------- /deb/kubectl/debian/kubectl.install: -------------------------------------------------------------------------------- 1 | usr/bin/kubectl usr/bin/ 2 | -------------------------------------------------------------------------------- /deb/kubectl/debian/postinst: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # see: dh_installdeb(1) 3 | 4 | set -o errexit 5 | set -o nounset 6 | 7 | # summary of how this script can be called: 8 | # * `configure' 9 | # * `abort-upgrade' 10 | # * `abort-remove' `in-favour' 11 | # 12 | # * `abort-remove' 13 | # * `abort-deconfigure' `in-favour' 14 | # `removing' 15 | # 16 | # for details, see https://www.debian.org/doc/debian-policy/ or 17 | # the debian-policy package 18 | 19 | 20 | case "$1" in 21 | configure) 22 | ;; 23 | 24 | abort-upgrade|abort-remove|abort-deconfigure) 25 | ;; 26 | 27 | *) 28 | echo "postinst called with unknown argument \`$1'" >&2 29 | exit 1 30 | ;; 31 | esac 32 | 33 | # dh_installdeb will replace this with shell code automatically 34 | # generated by other debhelper scripts. 35 | 36 | #DEBHELPER# 37 | 38 | exit 0 39 | -------------------------------------------------------------------------------- /deb/kubectl/debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | # -*- makefile -*- 3 | 4 | #export DH_VERBOSE=1 5 | 6 | build: 7 | echo noop 8 | 9 | binary: 10 | mkdir -p usr/bin 11 | cp kubectl usr/bin/kubectl 12 | chmod +x usr/bin/kubectl 13 | dh_testroot 14 | dh_auto_install 15 | dh_shlibdeps 16 | dh_install 17 | dh_installdeb 18 | dh_gencontrol 19 | dh_md5sums 20 | dh_builddeb 21 | 22 | %: 23 | dh $@ 24 | -------------------------------------------------------------------------------- /deb/kubectl/debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (native) 2 | -------------------------------------------------------------------------------- /deb/kubelet/debian/changelog: -------------------------------------------------------------------------------- 1 | kubelet (%{_version}-%{_release}) lts; urgency=medium 2 | 3 | * https://git.k8s.io/kubernetes/CHANGELOG/README.md 4 | -------------------------------------------------------------------------------- /deb/kubelet/debian/compat: -------------------------------------------------------------------------------- 1 | 9 2 | -------------------------------------------------------------------------------- /deb/kubelet/debian/control: -------------------------------------------------------------------------------- 1 | Source: kubelet 2 | Section: misc 3 | Priority: optional 4 | Maintainer: Kubernetes Authors 5 | Build-Depends: ca-certificates, debhelper (>= 9.20160709) 6 | Standards-Version: 3.9.4 7 | Homepage: https://kubernetes.io 8 | Vcs-Git: https://github.com/kubernetes/kubernetes.git 9 | Vcs-Browser: https://github.com/kubernetes/kubernetes 10 | 11 | Package: kubelet 12 | Architecture: %{_arch} 13 | Depends: iptables (>= 1.4.21), kubernetes-cni (>= 0.8.6), iproute2, socat, util-linux, mount, ebtables, ethtool, conntrack, ${misc:Depends} 14 | Description: Kubernetes Node Agent 15 | The node agent of Kubernetes, the container cluster manager 16 | -------------------------------------------------------------------------------- /deb/kubelet/debian/copyright: -------------------------------------------------------------------------------- 1 | Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ 2 | Upstream-Name: kubelet 3 | Source: https://github.com/kubernetes/kubernetes 4 | 5 | Files: * 6 | Copyright: 2016 The Kubernetes Authors. 7 | License: Apache-2.0 8 | Licensed under the Apache License, Version 2.0 (the "License"); 9 | you may not use this file except in compliance with the License. 10 | You may obtain a copy of the License at 11 | . 12 | http://www.apache.org/licenses/LICENSE-2.0 13 | . 14 | Unless required by applicable law or agreed to in writing, software 15 | distributed under the License is distributed on an "AS IS" BASIS, 16 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | See the License for the specific language governing permissions and 18 | limitations under the License. 19 | -------------------------------------------------------------------------------- /deb/kubelet/debian/kubelet.install: -------------------------------------------------------------------------------- 1 | usr/bin/kubelet usr/bin/ 2 | lib/systemd/system/kubelet.service lib/systemd/system/ 3 | -------------------------------------------------------------------------------- /deb/kubelet/debian/postinst: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # postinst script for kubelet 3 | # 4 | # see: dh_installdeb(1) 5 | 6 | set -o errexit 7 | set -o nounset 8 | 9 | # summary of how this script can be called: 10 | # * `configure' 11 | # * `abort-upgrade' 12 | # * `abort-remove' `in-favour' 13 | # 14 | # * `abort-remove' 15 | # * `abort-deconfigure' `in-favour' 16 | # `removing' 17 | # 18 | # for details, see https://www.debian.org/doc/debian-policy/ or 19 | # the debian-policy package 20 | 21 | 22 | case "$1" in 23 | configure) 24 | ;; 25 | 26 | abort-upgrade|abort-remove|abort-deconfigure) 27 | ;; 28 | 29 | *) 30 | echo "postinst called with unknown argument \`$1'" >&2 31 | exit 1 32 | ;; 33 | esac 34 | 35 | mkdir -p /etc/kubernetes/manifests 36 | 37 | # dh_installdeb will replace this with shell code automatically 38 | # generated by other debhelper scripts. 39 | 40 | #DEBHELPER# 41 | 42 | exit 0 43 | -------------------------------------------------------------------------------- /deb/kubelet/debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | # -*- makefile -*- 3 | 4 | #export DH_VERBOSE=1 5 | 6 | build: 7 | echo noop 8 | 9 | binary: 10 | mkdir -p usr/bin 11 | cp kubelet usr/bin/kubelet 12 | chmod +x usr/bin/kubelet 13 | dh_testroot 14 | dh_auto_install 15 | dh_shlibdeps 16 | dh_install 17 | dh_systemd_enable 18 | dh_installinit 19 | dh_systemd_start 20 | dh_installdeb 21 | dh_gencontrol 22 | dh_md5sums 23 | dh_builddeb 24 | 25 | %: 26 | dh $@ --with systemd 27 | -------------------------------------------------------------------------------- /deb/kubelet/debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (native) 2 | -------------------------------------------------------------------------------- /deb/kubelet/lib/systemd/system/kubelet.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=kubelet: The Kubernetes Node Agent 3 | Documentation=https://kubernetes.io/docs/home/ 4 | Wants=network-online.target 5 | After=network-online.target 6 | 7 | [Service] 8 | ExecStart=/usr/bin/kubelet 9 | Restart=always 10 | StartLimitInterval=0 11 | RestartSec=10 12 | 13 | [Install] 14 | WantedBy=multi-user.target 15 | -------------------------------------------------------------------------------- /hack/build_binaries.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -o errexit 4 | set -o nounset 5 | set -o pipefail 6 | 7 | source "kit/helper.sh" 8 | cd "${WORKDIR}" 9 | 10 | KUBE_BUILD_PLATFORMS=( 11 | linux/amd64 12 | linux/arm64 13 | ) 14 | for platform in ${KUBE_BUILD_PLATFORMS[*]}; do 15 | ./build/run.sh make KUBE_BUILD_PLATFORMS="${platform}" kubectl kubelet kubeadm 2>&1 | grep -v -E '^I\w+ ' || echo "fail ${platform}" 16 | done 17 | TARGETS=$(ls _output/dockerized/bin/*/*/{kubectl,kubelet,kubeadm}) 18 | 19 | rm -rf "${OUTPUT}" 20 | mkdir -p "${OUTPUT}" 21 | for target in $TARGETS; do 22 | dist=${target#_output/dockerized/bin/} 23 | mkdir -p "${OUTPUT}/${dist}" 24 | cp "${target}" "${OUTPUT}/${dist}/" 25 | done 26 | -------------------------------------------------------------------------------- /hack/build_image.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -o errexit 4 | set -o nounset 5 | set -o pipefail 6 | 7 | source "kit/helper.sh" 8 | cd "${WORKDIR}" 9 | 10 | KUBE_DOCKER_REGISTRY=${KUBE_DOCKER_REGISTRY:-} 11 | 12 | KUBE_BUILD_PLATFORMS=( 13 | linux/amd64 14 | linux/arm64 15 | ) 16 | for platform in ${KUBE_BUILD_PLATFORMS[*]}; do 17 | make KUBE_GIT_TREE_STATE=clean KUBE_BUILD_HYPERKUBE=n KUBE_BUILD_CONFORMANCE=n KUBE_BUILD_PULL_LATEST_IMAGES=n KUBE_RELEASE_RUN_TESTS=n KUBE_BUILD_PLATFORMS="${platform}" KUBE_DOCKER_REGISTRY="${KUBE_DOCKER_REGISTRY}" release-images || echo "fail ${platform}" 18 | done 19 | -------------------------------------------------------------------------------- /hack/checkout.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -o errexit 4 | set -o nounset 5 | set -o pipefail 6 | 7 | kit/checkout.sh $@ -------------------------------------------------------------------------------- /hack/format_all_patch.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -o errexit 4 | set -o nounset 5 | set -o pipefail 6 | 7 | kit/format_all_patch.sh 8 | -------------------------------------------------------------------------------- /hack/format_patch.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -o errexit 4 | set -o nounset 5 | set -o pipefail 6 | 7 | kit/format_patch.sh $@ 8 | -------------------------------------------------------------------------------- /hack/gen_verify_workflows.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -o errexit 4 | set -o nounset 5 | set -o pipefail 6 | 7 | source "kit/helper.sh" 8 | 9 | RELEASES=$(helper::config::list_releases) 10 | 11 | cat <&1 | grep -v -E '^I\w+ ' 13 | 14 | IMAGE=$(KUBE_RUN_COPY_OUTPUT=n ./build/run.sh ./_output/bin/kubeadm config images list | grep -v '+++' | grep -v "/kube-" | sed -E 's/\s+/ /g' | sed 's/-amd64:/:/g') 15 | 16 | cd "${ROOT}" 17 | ./hack/image_manifest_retags.sh ${IMAGE} 18 | -------------------------------------------------------------------------------- /hack/image_tag.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -o errexit 4 | set -o nounset 5 | set -o pipefail 6 | 7 | 8 | OLD_REGISTRY=${OLD_REGISTRY:-} 9 | REGISTRY=${REGISTRY:-} 10 | OLD_IMAGES=$(docker images | grep ${OLD_REGISTRY} | grep kube- | grep -v cross | awk '{print $1":"$2}') 11 | for old_image in ${OLD_IMAGES} ; do 12 | new_image=$(echo ${old_image} | sed "s#${OLD_REGISTRY}#${REGISTRY}#g") 13 | docker tag "${old_image}" "${new_image}" 14 | docker rmi "${old_image}" 15 | done 16 | -------------------------------------------------------------------------------- /hack/install_etcd.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -o errexit 4 | set -o nounset 5 | set -o pipefail 6 | 7 | source "kit/helper.sh" 8 | cd "${WORKDIR}" 9 | 10 | hack/install-etcd.sh 11 | export PATH="${WORKDIR}/third_party/etcd:${PATH}" 12 | 13 | etcd --version 14 | -------------------------------------------------------------------------------- /hack/kit.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -o errexit 4 | set -o nounset 5 | set -o pipefail 6 | 7 | git clone --single-branch --depth 1 https://github.com/klts-io/kit 8 | -------------------------------------------------------------------------------- /hack/pkg_deb.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -o errexit 4 | set -o nounset 5 | set -o pipefail 6 | 7 | source "kit/helper.sh" 8 | cd "${ROOT}" 9 | 10 | VERSION=$(helper::workdir::version) 11 | RELEASE="${VERSION##*-}" 12 | VERSION="${VERSION%-*}" 13 | 14 | if [[ "${VERSION}" == "${RELEASE}" ]]; then 15 | RELEASE="00" 16 | fi 17 | 18 | ${KITDIR}/pkg_deb.sh kubectl,kubelet,kubeadm amd64,arm64 "${VERSION}" "${RELEASE}" 19 | -------------------------------------------------------------------------------- /hack/pkg_rpm.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -o errexit 4 | set -o nounset 5 | set -o pipefail 6 | 7 | source "kit/helper.sh" 8 | cd "${ROOT}" 9 | 10 | VERSION=$(helper::workdir::version) 11 | RELEASE="${VERSION##*-}" 12 | VERSION="${VERSION%-*}" 13 | 14 | if [[ "${VERSION}" == "${RELEASE}" ]]; then 15 | RELEASE="00" 16 | fi 17 | 18 | ${KITDIR}/pkg_rpm.sh kubectl,kubelet,kubeadm amd64,arm64 "${VERSION}" "${RELEASE}" 19 | -------------------------------------------------------------------------------- /hack/public_source.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -o errexit 4 | set -o nounset 5 | set -o pipefail 6 | 7 | kit/public_source.sh 8 | -------------------------------------------------------------------------------- /hack/test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -o errexit 4 | set -o nounset 5 | set -o pipefail 6 | 7 | source "kit/helper.sh" 8 | cd "${WORKDIR}" 9 | 10 | TMPFILE="${TMPDIR}/test.log" 11 | 12 | ./build/run.sh make test 2>&1 | tee "${TMPFILE}" | grep -v -E '^I\w+ ' && exit 0 13 | 14 | RETRY_CASES=$(cat "${TMPFILE}" | grep -E '^FAIL\s+k8s.io/kubernetes' | awk '{print $2}' || echo "") 15 | 16 | TAG=$(helper::workdir::version) 17 | 18 | FAILURES_TOLERATED=$(helper::config::get_test_failures_tolerated ${TAG}) 19 | if [[ "${FAILURES_TOLERATED}" != "" ]]; then 20 | echo "+++ Test failed, the case is as follows:" 21 | echo "${RETRY_CASES}" 22 | echo "+++ Failures tolerated, the case is as follows:" 23 | echo "${FAILURES_TOLERATED}" 24 | 25 | for tolerate in ${FAILURES_TOLERATED}; do 26 | RETRY_CASES=$(echo "${RETRY_CASES}" | grep -v -E "^${tolerate}$" || echo "") 27 | done 28 | if [[ "${RETRY_CASES}" == "" ]]; then 29 | exit 0 30 | fi 31 | fi 32 | 33 | echo "+++ Test failed, will retry 5 times" 34 | for n in {1..5}; do 35 | echo "+++ Test retry ${n}, the case is as follows:" 36 | echo "${RETRY_CASES}" 37 | want=$(echo ${RETRY_CASES}) 38 | ./build/run.sh make test WHAT="${want}" 2>&1 | tee "${TMPFILE}" | grep -v -E '^I\w+ ' && exit 0 39 | RETRY_CASES=$(cat "${TMPFILE}" | grep -E '^FAIL\s+k8s.io/kubernetes' | awk '{print $2}' || echo "") 40 | done 41 | 42 | echo "!!! Test failed, the case is as follows:" 43 | echo "${RETRY_CASES}" 44 | 45 | exit 1 46 | -------------------------------------------------------------------------------- /hack/test_cmd.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -o errexit 4 | set -o nounset 5 | set -o pipefail 6 | 7 | source "kit/helper.sh" 8 | export KUBE_ROOT=$(dirname "$(readlink -f "$0")")/.. 9 | export TERM=linux 10 | echo "KUBE_ROOT directory: $KUBE_ROOT" 11 | cd "${WORKDIR}" 12 | 13 | # Kubeadm was added for testing in 1.19 and later 14 | for n in {1..5}; do 15 | echo "+++ Test retry ${n}" 16 | ./build/shell.sh -c ' 17 | 18 | # before v1.25 19 | make generated_files kubeadm 20 | # after v1.26 21 | ./build/run.sh make all WHAT=cmd/kubeadm 22 | 23 | mkdir -p _output/local/go/bin/ && cp _output/dockerized/bin/linux/amd64/kubeadm _output/local/go/bin/ 24 | TERM=linux PATH=$(pwd)/third_party/etcd:${PATH} make test-cmd 25 | ' 2>&1 | grep -v -E '^I\w+ ' && exit 0 26 | done 27 | -------------------------------------------------------------------------------- /hack/test_e2e.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -o errexit 4 | set -o nounset 5 | set -o pipefail 6 | 7 | source "kit/helper.sh" 8 | cd "${WORKDIR}" 9 | 10 | ./build/run.sh make test-e2e 2>&1 | grep -v -E '^I\w+ ' 11 | -------------------------------------------------------------------------------- /hack/test_e2e_node.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -o errexit 4 | set -o nounset 5 | set -o pipefail 6 | 7 | source "kit/helper.sh" 8 | cd "${WORKDIR}" 9 | 10 | ./build/run.sh make test-e2e-node 2>&1 | grep -v -E '^I\w+ ' 11 | -------------------------------------------------------------------------------- /hack/test_integration.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -o errexit 4 | set -o nounset 5 | set -o pipefail 6 | 7 | source "kit/helper.sh" 8 | export KUBE_ROOT=$(dirname "$(readlink -f "$0")")/.. 9 | export TERM=linux 10 | echo "KUBE_ROOT directory: $KUBE_ROOT" 11 | cd "${WORKDIR}" 12 | echo "WORKDIR directory: $WORKDIR" 13 | 14 | TMPFILE="${TMPDIR}/test-integration.log" 15 | 16 | # Etcd was added for testing in 1.21 and later 17 | function test-integration() { 18 | ./build/shell.sh -c ' 19 | # generate .make/go-pkgdeps.mk 20 | go install ./cmd/... 21 | 22 | # run test-integration 23 | KUBE_RUN_COPY_OUTPUT=y TERM=linux PATH=$(pwd)/third_party/etcd:${PATH} DBG_CODEGEN=1 make test-integration 24 | ' 25 | } 26 | 27 | test-integration 2>&1 | tee "${TMPFILE}" | grep -v -E '^I\w+ ' && exit 0 28 | 29 | echo "-------print TMPFILE:" 30 | cat "${TMPFILE}" 31 | echo "-------TMPFILE end." 32 | 33 | RETRY_CASES=$(cat "${TMPFILE}" | grep -E '^FAIL\s+k8s.io/kubernetes' | awk '{print $2}' || echo "") 34 | 35 | TAG=$(helper::workdir::version) 36 | 37 | FAILURES_TOLERATED=$(helper::config::get_test_integration_failures_tolerated ${TAG}) 38 | if [[ "${FAILURES_TOLERATED}" != "" ]]; then 39 | echo "+++ Test failed, the case is as follows:" 40 | echo "${RETRY_CASES}" 41 | echo "+++ Failures tolerated, the case is as follows:" 42 | echo "${FAILURES_TOLERATED}" 43 | 44 | for tolerate in ${FAILURES_TOLERATED}; do 45 | RETRY_CASES=$(echo "${RETRY_CASES}" | grep -v -E "^${tolerate}$" || echo "") 46 | done 47 | if [[ "${RETRY_CASES}" == "" ]]; then 48 | exit 0 49 | fi 50 | fi 51 | 52 | echo "+++ Test failed, will retry 5 times" 53 | for n in {1..5}; do 54 | echo "+++ Test retry ${n}, the case is as follows:" 55 | echo "${RETRY_CASES}" 56 | want=$(echo ${RETRY_CASES}) 57 | test-integration WHAT="${want}" 2>&1 | tee "${TMPFILE}" | grep -v -E '^I\w+ ' && exit 0 58 | RETRY_CASES=$(cat "${TMPFILE}" | grep -E '^FAIL\s+k8s.io/kubernetes' | awk '{print $2}' || echo "") 59 | done 60 | 61 | echo "!!! Test failed, the case is as follows:" 62 | echo "${RETRY_CASES}" 63 | 64 | exit 1 65 | -------------------------------------------------------------------------------- /hack/verify_build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -o errexit 4 | set -o nounset 5 | set -o pipefail 6 | 7 | source "kit/helper.sh" 8 | cd "${ROOT}" 9 | 10 | RELEASES=$(helper::config::list_releases) 11 | 12 | for release in ${RELEASES}; do 13 | echo "Verifying build release: ${release}" 14 | make "${release}" verify-build-client verify-build-server verify-build-image 15 | done 16 | -------------------------------------------------------------------------------- /hack/verify_build_client.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -o errexit 4 | set -o nounset 5 | set -o pipefail 6 | 7 | source "kit/helper.sh" 8 | cd "${WORKDIR}" 9 | 10 | KUBE_BUILD_PLATFORMS=( 11 | linux/amd64 12 | ) 13 | 14 | ./build/run.sh make KUBE_BUILD_PLATFORMS="${KUBE_BUILD_PLATFORMS}" kubectl 2>&1 | grep -v -E '^I\w+ ' || echo "client build failed" 15 | 16 | WANTS=( 17 | kubectl 18 | ) 19 | TARGETS=$(ls _output/dockerized/bin/*/*/*) 20 | FAILD=false 21 | for want in ${WANTS}; do 22 | if ! [[ "${TARGETS}" =~ "${want}" ]]; then 23 | FAILD=true 24 | echo "Missing ${want}" 25 | fi 26 | done 27 | 28 | if [[ "${FAILD}" == true ]]; then 29 | exit 1 30 | fi 31 | -------------------------------------------------------------------------------- /hack/verify_build_image.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -o errexit 4 | set -o nounset 5 | set -o pipefail 6 | 7 | source "kit/helper.sh" 8 | cd "${WORKDIR}" 9 | 10 | KUBE_BUILD_PLATFORMS=( 11 | linux/amd64 12 | ) 13 | 14 | make KUBE_GIT_TREE_STATE=clean KUBE_BUILD_HYPERKUBE=n KUBE_BUILD_CONFORMANCE=n KUBE_BUILD_PULL_LATEST_IMAGES=n KUBE_RELEASE_RUN_TESTS=n KUBE_BUILD_PLATFORMS="${KUBE_BUILD_PLATFORMS}" release-images || echo "image build failed" 15 | 16 | WANTS=( 17 | kube-controller-manager 18 | kube-scheduler 19 | kube-apiserver 20 | kube-proxy 21 | ) 22 | TARGETS=$(ls _output/release-images/*/*.tar) 23 | FAILD=false 24 | for want in ${WANTS}; do 25 | if ! [[ "${TARGETS}" =~ "${want}.tar" ]]; then 26 | FAILD=true 27 | echo "Missing ${want}.tar" 28 | fi 29 | done 30 | 31 | if [[ "${FAILD}" == true ]]; then 32 | exit 1 33 | fi 34 | -------------------------------------------------------------------------------- /hack/verify_build_server.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -o errexit 4 | set -o nounset 5 | set -o pipefail 6 | 7 | source "kit/helper.sh" 8 | cd "${WORKDIR}" 9 | 10 | KUBE_BUILD_PLATFORMS=( 11 | linux/amd64 12 | ) 13 | 14 | ./build/run.sh make KUBE_BUILD_PLATFORMS="${KUBE_BUILD_PLATFORMS}" kubelet kubeadm 2>&1 | grep -v -E '^I\w+ ' || echo "server build failed" 15 | 16 | WANTS=( 17 | kubelet 18 | kubeadm 19 | ) 20 | TARGETS=$(ls _output/dockerized/bin/*/*/*) 21 | FAILD=false 22 | for want in ${WANTS}; do 23 | if ! [[ "${TARGETS}" =~ "${want}" ]]; then 24 | FAILD=true 25 | echo "Missing ${want}" 26 | fi 27 | done 28 | 29 | if [[ "${FAILD}" == true ]]; then 30 | exit 1 31 | fi 32 | -------------------------------------------------------------------------------- /hack/verify_patch.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -o errexit 4 | set -o nounset 5 | set -o pipefail 6 | 7 | source "kit/helper.sh" 8 | cd "${ROOT}" 9 | 10 | RELEASES=$(helper::config::list_releases) 11 | 12 | make ${RELEASES} 13 | -------------------------------------------------------------------------------- /hack/verify_patch_format.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -o errexit 4 | set -o nounset 5 | set -o pipefail 6 | 7 | source "kit/helper.sh" 8 | cd "${ROOT}" 9 | 10 | cp -r patches patches.bak 11 | 12 | function cleanup() { 13 | rm -rf patches.bak 14 | } 15 | trap cleanup EXIT 16 | 17 | ${KITDIR}/format_all_patch.sh 18 | 19 | diff -a patches patches.bak 20 | -------------------------------------------------------------------------------- /hack/verify_pkg_deb_client.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -o errexit 4 | set -o nounset 5 | set -o pipefail 6 | 7 | source "kit/helper.sh" 8 | cd "${ROOT}" 9 | 10 | ./hack/pkg_deb.sh kubectl amd64 11 | -------------------------------------------------------------------------------- /hack/verify_pkg_deb_server.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -o errexit 4 | set -o nounset 5 | set -o pipefail 6 | 7 | source "kit/helper.sh" 8 | cd "${ROOT}" 9 | 10 | ./hack/pkg_deb.sh kubeadm,kubelet amd64 11 | -------------------------------------------------------------------------------- /hack/verify_pkg_rpm_client.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -o errexit 4 | set -o nounset 5 | set -o pipefail 6 | 7 | source "kit/helper.sh" 8 | cd "${ROOT}" 9 | 10 | ./hack/pkg_rpm.sh kubectl amd64 11 | -------------------------------------------------------------------------------- /hack/verify_pkg_rpm_server.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -o errexit 4 | set -o nounset 5 | set -o pipefail 6 | 7 | source "kit/helper.sh" 8 | cd "${ROOT}" 9 | 10 | ./hack/pkg_rpm.sh kubeadm,kubelet amd64 11 | -------------------------------------------------------------------------------- /hack/verify_releases.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | LIST=$(cat releases.yml | yq -r '.releases | .[] | .name, .base_release' | xargs -n 2 ) 4 | 5 | 6 | IFS=$'\n' 7 | for item in ${LIST} ; do 8 | name=$(echo ${item} | cut -d ' ' -f 1) 9 | base_release=$(echo ${item} | cut -d ' ' -f 2) 10 | if [[ "${name%%-*}" != "${base_release%%-*}" ]]; then 11 | echo "ERROR: ${name} is not a release of ${base_release}" 12 | exit 1 13 | fi 14 | done 15 | -------------------------------------------------------------------------------- /patches/CVE-2019-1002101.1.10.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Maciej Szulik 3 | Date: Tue, 5 Mar 2019 14:55:01 +0100 4 | Subject: [PATCH] Fix panic in kubectl cp command 5 | 6 | --- 7 | pkg/kubectl/cmd/cp.go | 29 +++++++++++- 8 | pkg/kubectl/cmd/cp_test.go | 92 +++++++++++++++++++++++++++++++++----- 9 | 2 files changed, 107 insertions(+), 14 deletions(-) 10 | 11 | diff --git a/pkg/kubectl/cmd/cp.go b/pkg/kubectl/cmd/cp.go 12 | index a438687ba3d..9b853a5ccaf 100644 13 | --- a/pkg/kubectl/cmd/cp.go 14 | +++ b/pkg/kubectl/cmd/cp.go 15 | @@ -244,6 +244,18 @@ func copyFromPod(f cmdutil.Factory, cmd *cobra.Command, cmderr io.Writer, src, d 16 | // stripPathShortcuts removes any leading or trailing "../" from a given path 17 | func stripPathShortcuts(p string) string { 18 | newPath := path.Clean(p) 19 | + trimmed := strings.TrimPrefix(newPath, "../") 20 | + 21 | + for trimmed != newPath { 22 | + newPath = trimmed 23 | + trimmed = strings.TrimPrefix(newPath, "../") 24 | + } 25 | + 26 | + // trim leftover {".", ".."} 27 | + if newPath == "." || newPath == ".." { 28 | + newPath = "" 29 | + } 30 | + 31 | if len(newPath) > 0 && string(newPath[0]) == "/" { 32 | return newPath[1:] 33 | } 34 | @@ -346,6 +358,12 @@ func untarAll(reader io.Reader, destFile, prefix string) error { 35 | } 36 | entrySeq++ 37 | mode := header.FileInfo().Mode() 38 | + // all the files will start with the prefix, which is the directory where 39 | + // they were located on the pod, we need to strip down that prefix, but 40 | + // if the prefix is missing it means the tar was tempered with 41 | + if !strings.HasPrefix(header.Name, prefix) { 42 | + return fmt.Errorf("tar contents corrupted") 43 | + } 44 | outFileName := path.Join(destFile, clean(header.Name[len(prefix):])) 45 | baseName := path.Dir(outFileName) 46 | if err := os.MkdirAll(baseName, 0755); err != nil { 47 | @@ -370,8 +388,15 @@ func untarAll(reader io.Reader, destFile, prefix string) error { 48 | } 49 | 50 | if mode&os.ModeSymlink != 0 { 51 | - err := os.Symlink(header.Linkname, outFileName) 52 | - if err != nil { 53 | + linkname := header.Linkname 54 | + // error is returned if linkname can't be made relative to destFile, 55 | + // but relative can end up being ../dir that's why we also need to 56 | + // verify if relative path is the same after Clean-ing 57 | + relative, err := filepath.Rel(destFile, linkname) 58 | + if path.IsAbs(linkname) && (err != nil || relative != stripPathShortcuts(relative)) { 59 | + continue 60 | + } 61 | + if err := os.Symlink(linkname, outFileName); err != nil { 62 | return err 63 | } 64 | } else { 65 | diff --git a/pkg/kubectl/cmd/cp_test.go b/pkg/kubectl/cmd/cp_test.go 66 | index b7c0eb48722..7dabc93793e 100644 67 | --- a/pkg/kubectl/cmd/cp_test.go 68 | +++ b/pkg/kubectl/cmd/cp_test.go 69 | @@ -118,26 +118,32 @@ func TestGetPrefix(t *testing.T) { 70 | } 71 | } 72 | 73 | -func TestTarUntar(t *testing.T) { 74 | - dir, err := ioutil.TempDir("", "input") 75 | - dir2, err2 := ioutil.TempDir("", "output") 76 | - if err != nil || err2 != nil { 77 | - t.Errorf("unexpected error: %v | %v", err, err2) 78 | +func checkErr(t *testing.T, err error) { 79 | + if err != nil { 80 | + t.Errorf("unexpected error: %v", err) 81 | t.FailNow() 82 | } 83 | +} 84 | + 85 | +func TestTarUntar(t *testing.T) { 86 | + dir, err := ioutil.TempDir("", "input") 87 | + checkErr(t, err) 88 | + dir2, err := ioutil.TempDir("", "output") 89 | + checkErr(t, err) 90 | + dir3, err := ioutil.TempDir("", "dir") 91 | + checkErr(t, err) 92 | + 93 | dir = dir + "/" 94 | defer func() { 95 | - if err := os.RemoveAll(dir); err != nil { 96 | - t.Errorf("Unexpected error cleaning up: %v", err) 97 | - } 98 | - if err := os.RemoveAll(dir2); err != nil { 99 | - t.Errorf("Unexpected error cleaning up: %v", err) 100 | - } 101 | + os.RemoveAll(dir) 102 | + os.RemoveAll(dir2) 103 | + os.RemoveAll(dir3) 104 | }() 105 | 106 | files := []struct { 107 | name string 108 | data string 109 | + omitted bool 110 | fileType FileType 111 | }{ 112 | { 113 | @@ -162,7 +168,24 @@ func TestTarUntar(t *testing.T) { 114 | }, 115 | { 116 | name: "gakki", 117 | + data: "tmp/gakki", 118 | + fileType: SymLink, 119 | + }, 120 | + { 121 | + name: "relative_to_dest", 122 | + data: path.Join(dir2, "foo"), 123 | + fileType: SymLink, 124 | + }, 125 | + { 126 | + name: "tricky_relative", 127 | + data: path.Join(dir3, "xyz"), 128 | + omitted: true, 129 | + fileType: SymLink, 130 | + }, 131 | + { 132 | + name: "absolute_path", 133 | data: "/tmp/gakki", 134 | + omitted: true, 135 | fileType: SymLink, 136 | }, 137 | } 138 | @@ -228,7 +251,12 @@ func TestTarUntar(t *testing.T) { 139 | } 140 | } else if file.fileType == SymLink { 141 | dest, err := os.Readlink(filePath) 142 | - 143 | + if file.omitted { 144 | + if err != nil && strings.Contains(err.Error(), "no such file or directory") { 145 | + continue 146 | + } 147 | + t.Fatalf("expected to omit symlink for %s", filePath) 148 | + } 149 | if err != nil { 150 | t.Fatalf("unexpected error: %v", err) 151 | } 152 | @@ -242,6 +270,46 @@ func TestTarUntar(t *testing.T) { 153 | } 154 | } 155 | 156 | +func TestTarUntarWrongPrefix(t *testing.T) { 157 | + dir, err := ioutil.TempDir("", "input") 158 | + checkErr(t, err) 159 | + dir2, err := ioutil.TempDir("", "output") 160 | + checkErr(t, err) 161 | + 162 | + dir = dir + "/" 163 | + defer func() { 164 | + os.RemoveAll(dir) 165 | + os.RemoveAll(dir2) 166 | + }() 167 | + 168 | + filepath := path.Join(dir, "foo") 169 | + if err := os.MkdirAll(path.Dir(filepath), 0755); err != nil { 170 | + t.Fatalf("unexpected error: %v", err) 171 | + } 172 | + f, err := os.Create(filepath) 173 | + if err != nil { 174 | + t.Fatalf("unexpected error: %v", err) 175 | + } 176 | + defer f.Close() 177 | + if _, err := io.Copy(f, bytes.NewBuffer([]byte("sample data"))); err != nil { 178 | + t.Fatalf("unexpected error: %v", err) 179 | + } 180 | + if err := f.Close(); err != nil { 181 | + t.Fatal(err) 182 | + } 183 | + 184 | + writer := &bytes.Buffer{} 185 | + if err := makeTar(dir, dir, writer); err != nil { 186 | + t.Fatalf("unexpected error: %v", err) 187 | + } 188 | + 189 | + reader := bytes.NewBuffer(writer.Bytes()) 190 | + err = untarAll(reader, dir2, "verylongprefix-showing-the-tar-was-tempered-with") 191 | + if err == nil || !strings.Contains(err.Error(), "tar contents corrupted") { 192 | + t.Fatalf("unexpected error: %v", err) 193 | + } 194 | +} 195 | + 196 | // TestCopyToLocalFileOrDir tests untarAll in two cases : 197 | // 1: copy pod file to local file 198 | // 2: copy pod file into local directory 199 | -------------------------------------------------------------------------------- /patches/CVE-2019-11246.1.10.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Tim Allclair 3 | Date: Fri, 12 Apr 2019 18:37:53 -0700 4 | Subject: [PATCH 1/2] Test kubectl cp escape 5 | 6 | --- 7 | pkg/kubectl/cmd/cp_test.go | 189 +++++++++++++++++++++++++++++++++++++ 8 | 1 file changed, 189 insertions(+) 9 | 10 | diff --git a/pkg/kubectl/cmd/cp_test.go b/pkg/kubectl/cmd/cp_test.go 11 | index 7dabc93793e..51b356a7eba 100644 12 | --- a/pkg/kubectl/cmd/cp_test.go 13 | +++ b/pkg/kubectl/cmd/cp_test.go 14 | @@ -29,6 +29,7 @@ import ( 15 | "strings" 16 | "testing" 17 | 18 | + "github.com/stretchr/testify/require" 19 | "k8s.io/api/core/v1" 20 | "k8s.io/apimachinery/pkg/api/errors" 21 | "k8s.io/apimachinery/pkg/runtime" 22 | @@ -644,3 +645,191 @@ func TestCopyToPod(t *testing.T) { 23 | }) 24 | } 25 | } 26 | + 27 | +func TestUntar(t *testing.T) { 28 | + testdir, err := ioutil.TempDir("", "test-untar") 29 | + require.NoError(t, err) 30 | + defer os.RemoveAll(testdir) 31 | + t.Logf("Test base: %s", testdir) 32 | + 33 | + const ( 34 | + dest = "base" 35 | + ) 36 | + 37 | + type file struct { 38 | + path string 39 | + linkTarget string // For link types 40 | + expected string // Expect to find the file here (or not, if empty) 41 | + } 42 | + files := []file{{ 43 | + // Absolute file within dest 44 | + path: filepath.Join(testdir, dest, "abs"), 45 | + expected: filepath.Join(testdir, dest, testdir, dest, "abs"), 46 | + }, { // Absolute file outside dest 47 | + path: filepath.Join(testdir, "abs-out"), 48 | + expected: filepath.Join(testdir, dest, testdir, "abs-out"), 49 | + }, { // Absolute nested file within dest 50 | + path: filepath.Join(testdir, dest, "nested/nest-abs"), 51 | + expected: filepath.Join(testdir, dest, testdir, dest, "nested/nest-abs"), 52 | + }, { // Absolute nested file outside dest 53 | + path: filepath.Join(testdir, dest, "nested/../../nest-abs-out"), 54 | + expected: filepath.Join(testdir, dest, testdir, "nest-abs-out"), 55 | + }, { // Relative file inside dest 56 | + path: "relative", 57 | + expected: filepath.Join(testdir, dest, "relative"), 58 | + }, { // Relative file outside dest 59 | + path: "../unrelative", 60 | + expected: filepath.Join(testdir, dest, "unrelative"), 61 | + }, { // Nested relative file inside dest 62 | + path: "nested/nest-rel", 63 | + expected: filepath.Join(testdir, dest, "nested/nest-rel"), 64 | + }, { // Nested relative file outside dest 65 | + path: "nested/../../nest-unrelative", 66 | + expected: filepath.Join(testdir, dest, "nest-unrelative"), 67 | + }} 68 | + 69 | + mkExpectation := func(expected, suffix string) string { 70 | + if expected == "" { 71 | + return "" 72 | + } 73 | + return expected + suffix 74 | + } 75 | + links := []file{} 76 | + for _, f := range files { 77 | + links = append(links, file{ 78 | + path: f.path + "-innerlink", 79 | + linkTarget: "link-target", 80 | + expected: mkExpectation(f.expected, "-innerlink"), 81 | + }, file{ 82 | + path: f.path + "-innerlink-abs", 83 | + linkTarget: filepath.Join(testdir, dest, "link-target"), 84 | + expected: "", 85 | + }, file{ 86 | + path: f.path + "-outerlink", 87 | + linkTarget: filepath.Join(backtick(f.path), "link-target"), 88 | + expected: "", 89 | + }, file{ 90 | + path: f.path + "-outerlink-abs", 91 | + linkTarget: filepath.Join(testdir, "link-target"), 92 | + expected: "", 93 | + }) 94 | + } 95 | + files = append(files, links...) 96 | + 97 | + // Test back-tick escaping through a symlink. 98 | + files = append(files, 99 | + file{ 100 | + path: "nested/again/back-link", 101 | + linkTarget: "../../nested", 102 | + expected: filepath.Join(testdir, dest, "nested/again/back-link"), 103 | + }, 104 | + file{ 105 | + path: "nested/again/back-link/../../../back-link-file", 106 | + expected: filepath.Join(testdir, dest, "back-link-file"), 107 | + }) 108 | + 109 | + // Test chaining back-tick symlinks. 110 | + files = append(files, 111 | + file{ 112 | + path: "nested/back-link-first", 113 | + linkTarget: "../", 114 | + expected: filepath.Join(testdir, dest, "nested/back-link-first"), 115 | + }, 116 | + file{ 117 | + path: "nested/back-link-first/back-link-second", 118 | + linkTarget: "../", 119 | + expected: filepath.Join(testdir, dest, "back-link-second"), 120 | + }, 121 | + file{ 122 | + path: "nested/back-link-first/back-link-second/back-link-term", 123 | + }) 124 | + 125 | + buf := &bytes.Buffer{} 126 | + tw := tar.NewWriter(buf) 127 | + expectations := map[string]bool{} 128 | + for _, f := range files { 129 | + if f.expected != "" { 130 | + expectations[f.expected] = false 131 | + } 132 | + if f.linkTarget == "" { 133 | + hdr := &tar.Header{ 134 | + Name: f.path, 135 | + Mode: 0666, 136 | + Size: int64(len(f.path)), 137 | + } 138 | + require.NoError(t, tw.WriteHeader(hdr), f.path) 139 | + _, err := tw.Write([]byte(f.path)) 140 | + require.NoError(t, err, f.path) 141 | + } else { 142 | + hdr := &tar.Header{ 143 | + Name: f.path, 144 | + Mode: int64(0777 | os.ModeSymlink), 145 | + Typeflag: tar.TypeSymlink, 146 | + Linkname: f.linkTarget, 147 | + } 148 | + require.NoError(t, tw.WriteHeader(hdr), f.path) 149 | + } 150 | + } 151 | + tw.Close() 152 | + 153 | + require.NoError(t, untarAll(buf, filepath.Join(testdir, dest), "")) 154 | + 155 | + filepath.Walk(testdir, func(path string, info os.FileInfo, err error) error { 156 | + if err != nil { 157 | + return err 158 | + } 159 | + if info.IsDir() { 160 | + return nil // Ignore directories. 161 | + } 162 | + if _, ok := expectations[path]; !ok { 163 | + t.Errorf("Unexpected file at %s", path) 164 | + } else { 165 | + expectations[path] = true 166 | + } 167 | + return nil 168 | + }) 169 | + for path, found := range expectations { 170 | + if !found { 171 | + t.Errorf("Missing expected file %s", path) 172 | + } 173 | + } 174 | +} 175 | + 176 | +// backtick returns a path to one directory up from the target 177 | +func backtick(target string) string { 178 | + rel, _ := filepath.Rel(filepath.Dir(target), "../") 179 | + return rel 180 | +} 181 | + 182 | +func createTmpFile(t *testing.T, filepath, data string) { 183 | + f, err := os.Create(filepath) 184 | + if err != nil { 185 | + t.Fatalf("unexpected error: %v", err) 186 | + } 187 | + defer f.Close() 188 | + if _, err := io.Copy(f, bytes.NewBuffer([]byte(data))); err != nil { 189 | + t.Fatalf("unexpected error: %v", err) 190 | + } 191 | + if err := f.Close(); err != nil { 192 | + t.Fatal(err) 193 | + } 194 | +} 195 | + 196 | +func cmpFileData(t *testing.T, filePath, data string) { 197 | + f, err := os.Open(filePath) 198 | + if err != nil { 199 | + t.Fatalf("unexpected error: %v", err) 200 | + } 201 | + 202 | + defer f.Close() 203 | + buff := &bytes.Buffer{} 204 | + if _, err := io.Copy(buff, f); err != nil { 205 | + t.Fatal(err) 206 | + } 207 | + if err := f.Close(); err != nil { 208 | + t.Fatal(err) 209 | + } 210 | + if data != string(buff.Bytes()) { 211 | + t.Fatalf("expected: %s, saw: %s", data, string(buff.Bytes())) 212 | + } 213 | +} 214 | 215 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 216 | From: Maciej Szulik 217 | Date: Tue, 16 Apr 2019 15:49:16 +0200 218 | Subject: [PATCH 2/2] Properly handle links in tar 219 | 220 | --- 221 | pkg/kubectl/cmd/BUILD | 1 + 222 | pkg/kubectl/cmd/cp.go | 99 +++++++++++++---------- 223 | pkg/kubectl/cmd/cp_test.go | 159 +++++++++++++++++++++++++++++++++++-- 224 | 3 files changed, 208 insertions(+), 51 deletions(-) 225 | 226 | diff --git a/pkg/kubectl/cmd/BUILD b/pkg/kubectl/cmd/BUILD 227 | index 45707367c48..e72ba1a7566 100644 228 | --- a/pkg/kubectl/cmd/BUILD 229 | +++ b/pkg/kubectl/cmd/BUILD 230 | @@ -233,6 +233,7 @@ go_test( 231 | "//vendor/github.com/googleapis/gnostic/OpenAPIv2:go_default_library", 232 | "//vendor/github.com/spf13/cobra:go_default_library", 233 | "//vendor/github.com/stretchr/testify/assert:go_default_library", 234 | + "//vendor/github.com/stretchr/testify/require:go_default_library", 235 | "//vendor/gopkg.in/yaml.v2:go_default_library", 236 | "//vendor/k8s.io/api/batch/v1:go_default_library", 237 | "//vendor/k8s.io/api/batch/v1beta1:go_default_library", 238 | diff --git a/pkg/kubectl/cmd/cp.go b/pkg/kubectl/cmd/cp.go 239 | index 9b853a5ccaf..d406d52cf0d 100644 240 | --- a/pkg/kubectl/cmd/cp.go 241 | +++ b/pkg/kubectl/cmd/cp.go 242 | @@ -343,9 +343,7 @@ func clean(fileName string) string { 243 | return path.Clean(string(os.PathSeparator) + fileName) 244 | } 245 | 246 | -func untarAll(reader io.Reader, destFile, prefix string) error { 247 | - entrySeq := -1 248 | - 249 | +func untarAll(reader io.Reader, destDir, prefix string) error { 250 | // TODO: use compression here? 251 | tarReader := tar.NewReader(reader) 252 | for { 253 | @@ -356,51 +354,60 @@ func untarAll(reader io.Reader, destFile, prefix string) error { 254 | } 255 | break 256 | } 257 | - entrySeq++ 258 | - mode := header.FileInfo().Mode() 259 | - // all the files will start with the prefix, which is the directory where 260 | + 261 | + // All the files will start with the prefix, which is the directory where 262 | // they were located on the pod, we need to strip down that prefix, but 263 | - // if the prefix is missing it means the tar was tempered with 264 | + // if the prefix is missing it means the tar was tempered with. 265 | + // For the case where prefix is empty we need to ensure that the path 266 | + // is not absolute, which also indicates the tar file was tempered with. 267 | if !strings.HasPrefix(header.Name, prefix) { 268 | return fmt.Errorf("tar contents corrupted") 269 | } 270 | - outFileName := path.Join(destFile, clean(header.Name[len(prefix):])) 271 | - baseName := path.Dir(outFileName) 272 | + 273 | + // basic file information 274 | + mode := header.FileInfo().Mode() 275 | + destFileName := path.Join(destDir, header.Name[len(prefix):]) 276 | + baseName := path.Dir(destFileName) 277 | + 278 | if err := os.MkdirAll(baseName, 0755); err != nil { 279 | return err 280 | } 281 | if header.FileInfo().IsDir() { 282 | - if err := os.MkdirAll(outFileName, 0755); err != nil { 283 | + if err := os.MkdirAll(destFileName, 0755); err != nil { 284 | return err 285 | } 286 | continue 287 | } 288 | 289 | - // handle coping remote file into local directory 290 | - if entrySeq == 0 && !header.FileInfo().IsDir() { 291 | - exists, err := dirExists(outFileName) 292 | - if err != nil { 293 | - return err 294 | - } 295 | - if exists { 296 | - outFileName = filepath.Join(outFileName, path.Base(clean(header.Name))) 297 | - } 298 | + // We need to ensure that the destination file is always within boundries 299 | + // of the destination directory. This prevents any kind of path traversal 300 | + // from within tar archive. 301 | + dir, file := filepath.Split(destFileName) 302 | + evaledPath, err := filepath.EvalSymlinks(dir) 303 | + if err != nil { 304 | + return err 305 | + } 306 | + // For scrutiny we verify both the actual destination as well as we follow 307 | + // all the links that might lead outside of the destination directory. 308 | + if !isDestRelative(destDir, destFileName) || !isDestRelative(destDir, filepath.Join(evaledPath, file)) { 309 | + fmt.Fprintf(os.Stderr, "warning: link %q is pointing to %q which is outside target destination, skipping\n", destFileName, header.Linkname) 310 | + continue 311 | } 312 | 313 | if mode&os.ModeSymlink != 0 { 314 | linkname := header.Linkname 315 | - // error is returned if linkname can't be made relative to destFile, 316 | - // but relative can end up being ../dir that's why we also need to 317 | - // verify if relative path is the same after Clean-ing 318 | - relative, err := filepath.Rel(destFile, linkname) 319 | - if path.IsAbs(linkname) && (err != nil || relative != stripPathShortcuts(relative)) { 320 | + // We need to ensure that the link destination is always within boundries 321 | + // of the destination directory. This prevents any kind of path traversal 322 | + // from within tar archive. 323 | + if !isDestRelative(destDir, linkJoin(destFileName, linkname)) { 324 | + fmt.Fprintf(os.Stderr, "warning: link %q is pointing to %q which is outside target destination, skipping\n", destFileName, header.Linkname) 325 | continue 326 | } 327 | - if err := os.Symlink(linkname, outFileName); err != nil { 328 | + if err := os.Symlink(linkname, destFileName); err != nil { 329 | return err 330 | } 331 | } else { 332 | - outFile, err := os.Create(outFileName) 333 | + outFile, err := os.Create(destFileName) 334 | if err != nil { 335 | return err 336 | } 337 | @@ -414,14 +421,32 @@ func untarAll(reader io.Reader, destFile, prefix string) error { 338 | } 339 | } 340 | 341 | - if entrySeq == -1 { 342 | - //if no file was copied 343 | - errInfo := fmt.Sprintf("error: %s no such file or directory", prefix) 344 | - return errors.New(errInfo) 345 | - } 346 | return nil 347 | } 348 | 349 | +// linkJoin joins base and link to get the final path to be created. 350 | +// It will consider whether link is an absolute path or not when returning result. 351 | +func linkJoin(base, link string) string { 352 | + if filepath.IsAbs(link) { 353 | + return link 354 | + } 355 | + return filepath.Join(base, link) 356 | +} 357 | + 358 | +// isDestRelative returns true if dest is pointing outside the base directory, 359 | +// false otherwise. 360 | +func isDestRelative(base, dest string) bool { 361 | + fullPath := dest 362 | + if !filepath.IsAbs(dest) { 363 | + fullPath = filepath.Join(base, dest) 364 | + } 365 | + relative, err := filepath.Rel(base, fullPath) 366 | + if err != nil { 367 | + return false 368 | + } 369 | + return relative == "." || relative == stripPathShortcuts(relative) 370 | +} 371 | + 372 | func getPrefix(file string) string { 373 | // tar strips the leading '/' if it's there, so we will too 374 | return strings.TrimLeft(file, "/") 375 | @@ -462,15 +487,3 @@ func execute(f cmdutil.Factory, cmd *cobra.Command, options *ExecOptions) error 376 | } 377 | return nil 378 | } 379 | - 380 | -// dirExists checks if a path exists and is a directory. 381 | -func dirExists(path string) (bool, error) { 382 | - fi, err := os.Stat(path) 383 | - if err == nil && fi.IsDir() { 384 | - return true, nil 385 | - } 386 | - if os.IsNotExist(err) { 387 | - return false, nil 388 | - } 389 | - return false, err 390 | -} 391 | diff --git a/pkg/kubectl/cmd/cp_test.go b/pkg/kubectl/cmd/cp_test.go 392 | index 51b356a7eba..5e5c3e6b72e 100644 393 | --- a/pkg/kubectl/cmd/cp_test.go 394 | +++ b/pkg/kubectl/cmd/cp_test.go 395 | @@ -19,6 +19,7 @@ package cmd 396 | import ( 397 | "archive/tar" 398 | "bytes" 399 | + "fmt" 400 | "io" 401 | "io/ioutil" 402 | "net/http" 403 | @@ -119,6 +120,128 @@ func TestGetPrefix(t *testing.T) { 404 | } 405 | } 406 | 407 | +func TestStripPathShortcuts(t *testing.T) { 408 | + tests := []struct { 409 | + name string 410 | + input string 411 | + expected string 412 | + }{ 413 | + { 414 | + name: "test single path shortcut prefix", 415 | + input: "../foo/bar", 416 | + expected: "foo/bar", 417 | + }, 418 | + { 419 | + name: "test multiple path shortcuts", 420 | + input: "../../foo/bar", 421 | + expected: "foo/bar", 422 | + }, 423 | + { 424 | + name: "test multiple path shortcuts with absolute path", 425 | + input: "/tmp/one/two/../../foo/bar", 426 | + expected: "tmp/foo/bar", 427 | + }, 428 | + { 429 | + name: "test multiple path shortcuts with no named directory", 430 | + input: "../../", 431 | + expected: "", 432 | + }, 433 | + { 434 | + name: "test multiple path shortcuts with no named directory and no trailing slash", 435 | + input: "../..", 436 | + expected: "", 437 | + }, 438 | + { 439 | + name: "test multiple path shortcuts with absolute path and filename containing leading dots", 440 | + input: "/tmp/one/two/../../foo/..bar", 441 | + expected: "tmp/foo/..bar", 442 | + }, 443 | + { 444 | + name: "test multiple path shortcuts with no named directory and filename containing leading dots", 445 | + input: "../...foo", 446 | + expected: "...foo", 447 | + }, 448 | + { 449 | + name: "test filename containing leading dots", 450 | + input: "...foo", 451 | + expected: "...foo", 452 | + }, 453 | + { 454 | + name: "test root directory", 455 | + input: "/", 456 | + expected: "", 457 | + }, 458 | + } 459 | + 460 | + for _, test := range tests { 461 | + out := stripPathShortcuts(test.input) 462 | + if out != test.expected { 463 | + t.Errorf("expected: %s, saw: %s", test.expected, out) 464 | + } 465 | + } 466 | +} 467 | +func TestIsDestRelative(t *testing.T) { 468 | + tests := []struct { 469 | + base string 470 | + dest string 471 | + relative bool 472 | + }{ 473 | + { 474 | + base: "/dir", 475 | + dest: "../link", 476 | + relative: false, 477 | + }, 478 | + { 479 | + base: "/dir", 480 | + dest: "../../link", 481 | + relative: false, 482 | + }, 483 | + { 484 | + base: "/dir", 485 | + dest: "/link", 486 | + relative: false, 487 | + }, 488 | + { 489 | + base: "/dir", 490 | + dest: "link", 491 | + relative: true, 492 | + }, 493 | + { 494 | + base: "/dir", 495 | + dest: "int/file/link", 496 | + relative: true, 497 | + }, 498 | + { 499 | + base: "/dir", 500 | + dest: "int/../link", 501 | + relative: true, 502 | + }, 503 | + { 504 | + base: "/dir", 505 | + dest: "/dir/link", 506 | + relative: true, 507 | + }, 508 | + { 509 | + base: "/dir", 510 | + dest: "/dir/int/../link", 511 | + relative: true, 512 | + }, 513 | + { 514 | + base: "/dir", 515 | + dest: "/dir/../../link", 516 | + relative: false, 517 | + }, 518 | + } 519 | + 520 | + for i, test := range tests { 521 | + t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { 522 | + if test.relative != isDestRelative(test.base, test.dest) { 523 | + t.Errorf("unexpected result for: base %q, dest %q", test.base, test.dest) 524 | + } 525 | + }) 526 | + } 527 | +} 528 | + 529 | func checkErr(t *testing.T, err error) { 530 | if err != nil { 531 | t.Errorf("unexpected error: %v", err) 532 | @@ -517,7 +640,6 @@ func TestBadTar(t *testing.T) { 533 | name string 534 | body string 535 | }{ 536 | - {"/prefix/../../../tmp/foo", "Up to temp"}, 537 | {"/prefix/foo/bar/../../home/bburns/names.txt", "Down and back"}, 538 | } 539 | for _, file := range files { 540 | @@ -679,13 +801,13 @@ func TestUntar(t *testing.T) { 541 | expected: filepath.Join(testdir, dest, "relative"), 542 | }, { // Relative file outside dest 543 | path: "../unrelative", 544 | - expected: filepath.Join(testdir, dest, "unrelative"), 545 | + expected: "", 546 | }, { // Nested relative file inside dest 547 | path: "nested/nest-rel", 548 | expected: filepath.Join(testdir, dest, "nested/nest-rel"), 549 | }, { // Nested relative file outside dest 550 | path: "nested/../../nest-unrelative", 551 | - expected: filepath.Join(testdir, dest, "nest-unrelative"), 552 | + expected: "", 553 | }} 554 | 555 | mkExpectation := func(expected, suffix string) string { 556 | @@ -694,6 +816,13 @@ func TestUntar(t *testing.T) { 557 | } 558 | return expected + suffix 559 | } 560 | + mkBacktickExpectation := func(expected, suffix string) string { 561 | + dir, _ := filepath.Split(filepath.Clean(expected)) 562 | + if len(strings.Split(dir, string(os.PathSeparator))) <= 1 { 563 | + return "" 564 | + } 565 | + return expected + suffix 566 | + } 567 | links := []file{} 568 | for _, f := range files { 569 | links = append(links, file{ 570 | @@ -703,11 +832,11 @@ func TestUntar(t *testing.T) { 571 | }, file{ 572 | path: f.path + "-innerlink-abs", 573 | linkTarget: filepath.Join(testdir, dest, "link-target"), 574 | - expected: "", 575 | + expected: mkExpectation(f.expected, "-innerlink-abs"), 576 | }, file{ 577 | path: f.path + "-outerlink", 578 | linkTarget: filepath.Join(backtick(f.path), "link-target"), 579 | - expected: "", 580 | + expected: mkBacktickExpectation(f.expected, "-outerlink"), 581 | }, file{ 582 | path: f.path + "-outerlink-abs", 583 | linkTarget: filepath.Join(testdir, "link-target"), 584 | @@ -741,7 +870,19 @@ func TestUntar(t *testing.T) { 585 | expected: filepath.Join(testdir, dest, "back-link-second"), 586 | }, 587 | file{ 588 | - path: "nested/back-link-first/back-link-second/back-link-term", 589 | + // This case is chaining together symlinks that step back, so that 590 | + // if you just look at the target relative to the path it appears 591 | + // inside the destination directory, but if you actually follow each 592 | + // step of the path you end up outside the destination directory. 593 | + path: "nested/back-link-first/back-link-second/back-link-term", 594 | + linkTarget: "", 595 | + expected: "", 596 | + }) 597 | + 598 | + files = append(files, 599 | + file{ // Relative directory path with terminating / 600 | + path: "direct/dir/", 601 | + expected: "", 602 | }) 603 | 604 | buf := &bytes.Buffer{} 605 | @@ -758,8 +899,10 @@ func TestUntar(t *testing.T) { 606 | Size: int64(len(f.path)), 607 | } 608 | require.NoError(t, tw.WriteHeader(hdr), f.path) 609 | - _, err := tw.Write([]byte(f.path)) 610 | - require.NoError(t, err, f.path) 611 | + if !strings.HasSuffix(f.path, "/") { 612 | + _, err := tw.Write([]byte(f.path)) 613 | + require.NoError(t, err, f.path) 614 | + } 615 | } else { 616 | hdr := &tar.Header{ 617 | Name: f.path, 618 | -------------------------------------------------------------------------------- /patches/CVE-2019-11247.1.11.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: "Dr. Stefan Schimanski" 3 | Date: Mon, 1 Jul 2019 21:24:02 +0200 4 | Subject: [PATCH] apiextensions: 404 if request scope does not match crd scope 5 | 6 | --- 7 | .../pkg/apiserver/customresource_handler.go | 19 +++++++++++++++++++ 8 | 1 file changed, 19 insertions(+) 9 | 10 | diff --git a/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/customresource_handler.go b/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/customresource_handler.go 11 | index 7be3711dc17..63cd6a90fc3 100644 12 | --- a/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/customresource_handler.go 13 | +++ b/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/customresource_handler.go 14 | @@ -43,6 +43,7 @@ import ( 15 | "k8s.io/apimachinery/pkg/runtime/serializer/versioning" 16 | "k8s.io/apimachinery/pkg/types" 17 | utilruntime "k8s.io/apimachinery/pkg/util/runtime" 18 | + "k8s.io/apimachinery/pkg/util/sets" 19 | "k8s.io/apiserver/pkg/admission" 20 | "k8s.io/apiserver/pkg/endpoints/handlers" 21 | "k8s.io/apiserver/pkg/endpoints/handlers/responsewriters" 22 | @@ -153,6 +154,10 @@ func NewCustomResourceDefinitionHandler( 23 | return ret 24 | } 25 | 26 | +// possiblyAcrossAllNamespacesVerbs contains those verbs which can be per-namespace and across all 27 | +// namespaces for namespaces resources. I.e. for these an empty namespace in the requestInfo is fine. 28 | +var possiblyAcrossAllNamespacesVerbs = sets.NewString("list", "watch") 29 | + 30 | func (r *crdHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { 31 | ctx := req.Context() 32 | requestInfo, ok := apirequest.RequestInfoFrom(ctx) 33 | @@ -188,10 +193,24 @@ func (r *crdHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { 34 | http.Error(w, err.Error(), http.StatusInternalServerError) 35 | return 36 | } 37 | + 38 | + // if the scope in the CRD and the scope in request differ (with exception of the verbs in possiblyAcrossAllNamespacesVerbs 39 | + // for namespaced resources), pass request to the delegate, which is supposed to lead to a 404. 40 | + namespacedCRD, namespacedReq := crd.Spec.Scope == apiextensions.NamespaceScoped, len(requestInfo.Namespace) > 0 41 | + if !namespacedCRD && namespacedReq { 42 | + r.delegate.ServeHTTP(w, req) 43 | + return 44 | + } 45 | + if namespacedCRD && !namespacedReq && !possiblyAcrossAllNamespacesVerbs.Has(requestInfo.Verb) { 46 | + r.delegate.ServeHTTP(w, req) 47 | + return 48 | + } 49 | + 50 | if !apiextensions.HasServedCRDVersion(crd, requestInfo.APIVersion) { 51 | r.delegate.ServeHTTP(w, req) 52 | return 53 | } 54 | + 55 | // There is a small chance that a CRD is being served because NamesAccepted condition is true, 56 | // but it becomes "unserved" because another names update leads to a conflict 57 | // and EstablishingController wasn't fast enough to put the CRD into the Established condition. 58 | -------------------------------------------------------------------------------- /patches/CVE-2019-11248.1.11.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Tim Allclair 3 | Date: Thu, 16 May 2019 17:31:16 -0700 4 | Subject: [PATCH] Avoid the default server mux 5 | 6 | --- 7 | cmd/kubelet/app/server.go | 5 +++-- 8 | staging/src/k8s.io/apiserver/pkg/server/healthz/doc.go | 2 +- 9 | .../src/k8s.io/apiserver/pkg/server/healthz/healthz.go | 10 ---------- 10 | 3 files changed, 4 insertions(+), 13 deletions(-) 11 | 12 | diff --git a/cmd/kubelet/app/server.go b/cmd/kubelet/app/server.go 13 | index bcd5ea562ae..ab816ae2d88 100644 14 | --- a/cmd/kubelet/app/server.go 15 | +++ b/cmd/kubelet/app/server.go 16 | @@ -726,9 +726,10 @@ func run(s *options.KubeletServer, kubeDeps *kubelet.Dependencies, stopCh <-chan 17 | } 18 | 19 | if s.HealthzPort > 0 { 20 | - healthz.DefaultHealthz() 21 | + mux := http.NewServeMux() 22 | + healthz.InstallHandler(mux) 23 | go wait.Until(func() { 24 | - err := http.ListenAndServe(net.JoinHostPort(s.HealthzBindAddress, strconv.Itoa(int(s.HealthzPort))), nil) 25 | + err := http.ListenAndServe(net.JoinHostPort(s.HealthzBindAddress, strconv.Itoa(int(s.HealthzPort))), mux) 26 | if err != nil { 27 | glog.Errorf("Starting health server failed: %v", err) 28 | } 29 | diff --git a/staging/src/k8s.io/apiserver/pkg/server/healthz/doc.go b/staging/src/k8s.io/apiserver/pkg/server/healthz/doc.go 30 | index 06e67f6fe3c..d938caa3713 100644 31 | --- a/staging/src/k8s.io/apiserver/pkg/server/healthz/doc.go 32 | +++ b/staging/src/k8s.io/apiserver/pkg/server/healthz/doc.go 33 | @@ -17,5 +17,5 @@ limitations under the License. 34 | // Package healthz implements basic http server health checking. 35 | // Usage: 36 | // import "k8s.io/apiserver/pkg/server/healthz" 37 | -// healthz.DefaultHealthz() 38 | +// healthz.InstallHandler(mux) 39 | package healthz // import "k8s.io/apiserver/pkg/server/healthz" 40 | diff --git a/staging/src/k8s.io/apiserver/pkg/server/healthz/healthz.go b/staging/src/k8s.io/apiserver/pkg/server/healthz/healthz.go 41 | index 991618238ea..aa5c77559bd 100644 42 | --- a/staging/src/k8s.io/apiserver/pkg/server/healthz/healthz.go 43 | +++ b/staging/src/k8s.io/apiserver/pkg/server/healthz/healthz.go 44 | @@ -21,7 +21,6 @@ import ( 45 | "fmt" 46 | "net/http" 47 | "strings" 48 | - "sync" 49 | 50 | "github.com/golang/glog" 51 | 52 | @@ -34,15 +33,6 @@ type HealthzChecker interface { 53 | Check(req *http.Request) error 54 | } 55 | 56 | -var defaultHealthz = sync.Once{} 57 | - 58 | -// DefaultHealthz installs the default healthz check to the http.DefaultServeMux. 59 | -func DefaultHealthz(checks ...HealthzChecker) { 60 | - defaultHealthz.Do(func() { 61 | - InstallHandler(http.DefaultServeMux, checks...) 62 | - }) 63 | -} 64 | - 65 | // PingHealthz returns true automatically when checked 66 | var PingHealthz HealthzChecker = ping{} 67 | 68 | -------------------------------------------------------------------------------- /patches/CVE-2019-11249.1.10.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: M00nF1sh 3 | Date: Mon, 24 Jun 2019 11:16:00 -0700 4 | Subject: [PATCH 1/2] refactors to kubernetes CP command 5 | 6 | --- 7 | pkg/kubectl/cmd/cp.go | 5 +---- 8 | pkg/kubectl/cmd/cp_test.go | 36 ++++++++++++++++-------------------- 9 | 2 files changed, 17 insertions(+), 24 deletions(-) 10 | 11 | diff --git a/pkg/kubectl/cmd/cp.go b/pkg/kubectl/cmd/cp.go 12 | index d406d52cf0d..18a5c0176bc 100644 13 | --- a/pkg/kubectl/cmd/cp.go 14 | +++ b/pkg/kubectl/cmd/cp.go 15 | @@ -430,16 +430,13 @@ func linkJoin(base, link string) string { 16 | if filepath.IsAbs(link) { 17 | return link 18 | } 19 | - return filepath.Join(base, link) 20 | + return filepath.Join(filepath.Dir(base), link) 21 | } 22 | 23 | // isDestRelative returns true if dest is pointing outside the base directory, 24 | // false otherwise. 25 | func isDestRelative(base, dest string) bool { 26 | fullPath := dest 27 | - if !filepath.IsAbs(dest) { 28 | - fullPath = filepath.Join(base, dest) 29 | - } 30 | relative, err := filepath.Rel(base, fullPath) 31 | if err != nil { 32 | return false 33 | diff --git a/pkg/kubectl/cmd/cp_test.go b/pkg/kubectl/cmd/cp_test.go 34 | index 5e5c3e6b72e..7b58cd92f4b 100644 35 | --- a/pkg/kubectl/cmd/cp_test.go 36 | +++ b/pkg/kubectl/cmd/cp_test.go 37 | @@ -188,12 +188,12 @@ func TestIsDestRelative(t *testing.T) { 38 | }{ 39 | { 40 | base: "/dir", 41 | - dest: "../link", 42 | + dest: "/dir/../link", 43 | relative: false, 44 | }, 45 | { 46 | base: "/dir", 47 | - dest: "../../link", 48 | + dest: "/dir/../../link", 49 | relative: false, 50 | }, 51 | { 52 | @@ -203,32 +203,27 @@ func TestIsDestRelative(t *testing.T) { 53 | }, 54 | { 55 | base: "/dir", 56 | - dest: "link", 57 | + dest: "/dir/link", 58 | relative: true, 59 | }, 60 | { 61 | base: "/dir", 62 | - dest: "int/file/link", 63 | + dest: "/dir/int/../link", 64 | relative: true, 65 | }, 66 | { 67 | - base: "/dir", 68 | - dest: "int/../link", 69 | + base: "dir", 70 | + dest: "dir/link", 71 | relative: true, 72 | }, 73 | { 74 | - base: "/dir", 75 | - dest: "/dir/link", 76 | + base: "dir", 77 | + dest: "dir/int/../link", 78 | relative: true, 79 | }, 80 | { 81 | - base: "/dir", 82 | - dest: "/dir/int/../link", 83 | - relative: true, 84 | - }, 85 | - { 86 | - base: "/dir", 87 | - dest: "/dir/../../link", 88 | + base: "dir", 89 | + dest: "dir/../../link", 90 | relative: false, 91 | }, 92 | } 93 | @@ -816,9 +811,10 @@ func TestUntar(t *testing.T) { 94 | } 95 | return expected + suffix 96 | } 97 | - mkBacktickExpectation := func(expected, suffix string) string { 98 | - dir, _ := filepath.Split(filepath.Clean(expected)) 99 | - if len(strings.Split(dir, string(os.PathSeparator))) <= 1 { 100 | + mkBacktickExpectation := func(path, expected, suffix string) string { 101 | + linkTarget := filepath.Join(backtick(path), "link-target") 102 | + baseDir := filepath.Join(testdir, dest) 103 | + if !isDestRelative(baseDir, linkJoin(filepath.Join(baseDir, path), linkTarget)) { 104 | return "" 105 | } 106 | return expected + suffix 107 | @@ -836,7 +832,7 @@ func TestUntar(t *testing.T) { 108 | }, file{ 109 | path: f.path + "-outerlink", 110 | linkTarget: filepath.Join(backtick(f.path), "link-target"), 111 | - expected: mkBacktickExpectation(f.expected, "-outerlink"), 112 | + expected: mkBacktickExpectation(f.path, f.expected, "-outerlink"), 113 | }, file{ 114 | path: f.path + "-outerlink-abs", 115 | linkTarget: filepath.Join(testdir, "link-target"), 116 | @@ -940,7 +936,7 @@ func TestUntar(t *testing.T) { 117 | 118 | // backtick returns a path to one directory up from the target 119 | func backtick(target string) string { 120 | - rel, _ := filepath.Rel(filepath.Dir(target), "../") 121 | + rel := filepath.Join(filepath.Dir(target), "../") 122 | return rel 123 | } 124 | 125 | 126 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 127 | From: Tim Allclair 128 | Date: Fri, 12 Jul 2019 11:53:10 -0700 129 | Subject: [PATCH 2/2] refactors to kubernetes cp command 130 | 131 | --- 132 | pkg/kubectl/cmd/cp.go | 34 +++++------ 133 | pkg/kubectl/cmd/cp_test.go | 119 +++++++++++++++++++++---------------- 134 | 2 files changed, 84 insertions(+), 69 deletions(-) 135 | 136 | diff --git a/pkg/kubectl/cmd/cp.go b/pkg/kubectl/cmd/cp.go 137 | index 18a5c0176bc..228ce3f7368 100644 138 | --- a/pkg/kubectl/cmd/cp.go 139 | +++ b/pkg/kubectl/cmd/cp.go 140 | @@ -366,9 +366,14 @@ func untarAll(reader io.Reader, destDir, prefix string) error { 141 | 142 | // basic file information 143 | mode := header.FileInfo().Mode() 144 | - destFileName := path.Join(destDir, header.Name[len(prefix):]) 145 | - baseName := path.Dir(destFileName) 146 | + destFileName := filepath.Join(destDir, header.Name[len(prefix):]) 147 | 148 | + if !isDestRelative(destDir, destFileName) { 149 | + fmt.Fprintf(os.Stderr, "warning: file %q is outside target destination, skipping\n", destFileName) 150 | + continue 151 | + } 152 | + 153 | + baseName := filepath.Dir(destFileName) 154 | if err := os.MkdirAll(baseName, 0755); err != nil { 155 | return err 156 | } 157 | @@ -382,15 +387,14 @@ func untarAll(reader io.Reader, destDir, prefix string) error { 158 | // We need to ensure that the destination file is always within boundries 159 | // of the destination directory. This prevents any kind of path traversal 160 | // from within tar archive. 161 | - dir, file := filepath.Split(destFileName) 162 | - evaledPath, err := filepath.EvalSymlinks(dir) 163 | + evaledPath, err := filepath.EvalSymlinks(baseName) 164 | if err != nil { 165 | return err 166 | } 167 | // For scrutiny we verify both the actual destination as well as we follow 168 | // all the links that might lead outside of the destination directory. 169 | - if !isDestRelative(destDir, destFileName) || !isDestRelative(destDir, filepath.Join(evaledPath, file)) { 170 | - fmt.Fprintf(os.Stderr, "warning: link %q is pointing to %q which is outside target destination, skipping\n", destFileName, header.Linkname) 171 | + if !isDestRelative(destDir, filepath.Join(evaledPath, filepath.Base(destFileName))) { 172 | + fmt.Fprintf(os.Stderr, "warning: file %q is outside target destination, skipping\n", destFileName) 173 | continue 174 | } 175 | 176 | @@ -399,7 +403,11 @@ func untarAll(reader io.Reader, destDir, prefix string) error { 177 | // We need to ensure that the link destination is always within boundries 178 | // of the destination directory. This prevents any kind of path traversal 179 | // from within tar archive. 180 | - if !isDestRelative(destDir, linkJoin(destFileName, linkname)) { 181 | + linkTarget := linkname 182 | + if !filepath.IsAbs(linkname) { 183 | + linkTarget = filepath.Join(evaledPath, linkname) 184 | + } 185 | + if !isDestRelative(destDir, linkTarget) { 186 | fmt.Fprintf(os.Stderr, "warning: link %q is pointing to %q which is outside target destination, skipping\n", destFileName, header.Linkname) 187 | continue 188 | } 189 | @@ -424,20 +432,10 @@ func untarAll(reader io.Reader, destDir, prefix string) error { 190 | return nil 191 | } 192 | 193 | -// linkJoin joins base and link to get the final path to be created. 194 | -// It will consider whether link is an absolute path or not when returning result. 195 | -func linkJoin(base, link string) string { 196 | - if filepath.IsAbs(link) { 197 | - return link 198 | - } 199 | - return filepath.Join(filepath.Dir(base), link) 200 | -} 201 | - 202 | // isDestRelative returns true if dest is pointing outside the base directory, 203 | // false otherwise. 204 | func isDestRelative(base, dest string) bool { 205 | - fullPath := dest 206 | - relative, err := filepath.Rel(base, fullPath) 207 | + relative, err := filepath.Rel(base, dest) 208 | if err != nil { 209 | return false 210 | } 211 | diff --git a/pkg/kubectl/cmd/cp_test.go b/pkg/kubectl/cmd/cp_test.go 212 | index 7b58cd92f4b..6795499f9e1 100644 213 | --- a/pkg/kubectl/cmd/cp_test.go 214 | +++ b/pkg/kubectl/cmd/cp_test.go 215 | @@ -30,6 +30,7 @@ import ( 216 | "strings" 217 | "testing" 218 | 219 | + "github.com/stretchr/testify/assert" 220 | "github.com/stretchr/testify/require" 221 | "k8s.io/api/core/v1" 222 | "k8s.io/apimachinery/pkg/api/errors" 223 | @@ -769,9 +770,7 @@ func TestUntar(t *testing.T) { 224 | defer os.RemoveAll(testdir) 225 | t.Logf("Test base: %s", testdir) 226 | 227 | - const ( 228 | - dest = "base" 229 | - ) 230 | + basedir := filepath.Join(testdir, "base") 231 | 232 | type file struct { 233 | path string 234 | @@ -780,26 +779,26 @@ func TestUntar(t *testing.T) { 235 | } 236 | files := []file{{ 237 | // Absolute file within dest 238 | - path: filepath.Join(testdir, dest, "abs"), 239 | - expected: filepath.Join(testdir, dest, testdir, dest, "abs"), 240 | + path: filepath.Join(basedir, "abs"), 241 | + expected: filepath.Join(basedir, basedir, "abs"), 242 | }, { // Absolute file outside dest 243 | path: filepath.Join(testdir, "abs-out"), 244 | - expected: filepath.Join(testdir, dest, testdir, "abs-out"), 245 | + expected: filepath.Join(basedir, testdir, "abs-out"), 246 | }, { // Absolute nested file within dest 247 | - path: filepath.Join(testdir, dest, "nested/nest-abs"), 248 | - expected: filepath.Join(testdir, dest, testdir, dest, "nested/nest-abs"), 249 | + path: filepath.Join(basedir, "nested/nest-abs"), 250 | + expected: filepath.Join(basedir, basedir, "nested/nest-abs"), 251 | }, { // Absolute nested file outside dest 252 | - path: filepath.Join(testdir, dest, "nested/../../nest-abs-out"), 253 | - expected: filepath.Join(testdir, dest, testdir, "nest-abs-out"), 254 | + path: filepath.Join(basedir, "nested/../../nest-abs-out"), 255 | + expected: filepath.Join(basedir, testdir, "nest-abs-out"), 256 | }, { // Relative file inside dest 257 | path: "relative", 258 | - expected: filepath.Join(testdir, dest, "relative"), 259 | + expected: filepath.Join(basedir, "relative"), 260 | }, { // Relative file outside dest 261 | path: "../unrelative", 262 | expected: "", 263 | }, { // Nested relative file inside dest 264 | path: "nested/nest-rel", 265 | - expected: filepath.Join(testdir, dest, "nested/nest-rel"), 266 | + expected: filepath.Join(basedir, "nested/nest-rel"), 267 | }, { // Nested relative file outside dest 268 | path: "nested/../../nest-unrelative", 269 | expected: "", 270 | @@ -811,10 +810,11 @@ func TestUntar(t *testing.T) { 271 | } 272 | return expected + suffix 273 | } 274 | - mkBacktickExpectation := func(path, expected, suffix string) string { 275 | - linkTarget := filepath.Join(backtick(path), "link-target") 276 | - baseDir := filepath.Join(testdir, dest) 277 | - if !isDestRelative(baseDir, linkJoin(filepath.Join(baseDir, path), linkTarget)) { 278 | + mkBacklinkExpectation := func(expected, suffix string) string { 279 | + // "resolve" the back link relative to the expectation 280 | + targetDir := filepath.Dir(filepath.Dir(expected)) 281 | + // If the "resolved" target is not nested in basedir, it is escaping. 282 | + if !filepath.HasPrefix(targetDir, basedir) { 283 | return "" 284 | } 285 | return expected + suffix 286 | @@ -827,17 +827,27 @@ func TestUntar(t *testing.T) { 287 | expected: mkExpectation(f.expected, "-innerlink"), 288 | }, file{ 289 | path: f.path + "-innerlink-abs", 290 | - linkTarget: filepath.Join(testdir, dest, "link-target"), 291 | + linkTarget: filepath.Join(basedir, "link-target"), 292 | expected: mkExpectation(f.expected, "-innerlink-abs"), 293 | }, file{ 294 | - path: f.path + "-outerlink", 295 | - linkTarget: filepath.Join(backtick(f.path), "link-target"), 296 | - expected: mkBacktickExpectation(f.path, f.expected, "-outerlink"), 297 | + path: f.path + "-backlink", 298 | + linkTarget: filepath.Join("..", "link-target"), 299 | + expected: mkBacklinkExpectation(f.expected, "-backlink"), 300 | }, file{ 301 | path: f.path + "-outerlink-abs", 302 | linkTarget: filepath.Join(testdir, "link-target"), 303 | expected: "", 304 | }) 305 | + 306 | + if f.expected != "" { 307 | + // outerlink is the number of backticks to escape to testdir 308 | + outerlink, _ := filepath.Rel(f.expected, testdir) 309 | + links = append(links, file{ 310 | + path: f.path + "outerlink", 311 | + linkTarget: filepath.Join(outerlink, "link-target"), 312 | + expected: "", 313 | + }) 314 | + } 315 | } 316 | files = append(files, links...) 317 | 318 | @@ -846,11 +856,11 @@ func TestUntar(t *testing.T) { 319 | file{ 320 | path: "nested/again/back-link", 321 | linkTarget: "../../nested", 322 | - expected: filepath.Join(testdir, dest, "nested/again/back-link"), 323 | + expected: filepath.Join(basedir, "nested/again/back-link"), 324 | }, 325 | file{ 326 | path: "nested/again/back-link/../../../back-link-file", 327 | - expected: filepath.Join(testdir, dest, "back-link-file"), 328 | + expected: filepath.Join(basedir, "back-link-file"), 329 | }) 330 | 331 | // Test chaining back-tick symlinks. 332 | @@ -858,20 +868,11 @@ func TestUntar(t *testing.T) { 333 | file{ 334 | path: "nested/back-link-first", 335 | linkTarget: "../", 336 | - expected: filepath.Join(testdir, dest, "nested/back-link-first"), 337 | + expected: filepath.Join(basedir, "nested/back-link-first"), 338 | }, 339 | file{ 340 | path: "nested/back-link-first/back-link-second", 341 | linkTarget: "../", 342 | - expected: filepath.Join(testdir, dest, "back-link-second"), 343 | - }, 344 | - file{ 345 | - // This case is chaining together symlinks that step back, so that 346 | - // if you just look at the target relative to the path it appears 347 | - // inside the destination directory, but if you actually follow each 348 | - // step of the path you end up outside the destination directory. 349 | - path: "nested/back-link-first/back-link-second/back-link-term", 350 | - linkTarget: "", 351 | expected: "", 352 | }) 353 | 354 | @@ -934,10 +935,32 @@ func TestUntar(t *testing.T) { 355 | } 356 | } 357 | 358 | -// backtick returns a path to one directory up from the target 359 | -func backtick(target string) string { 360 | - rel := filepath.Join(filepath.Dir(target), "../") 361 | - return rel 362 | +func TestUntar_SingleFile(t *testing.T) { 363 | + testdir, err := ioutil.TempDir("", "test-untar") 364 | + require.NoError(t, err) 365 | + defer os.RemoveAll(testdir) 366 | + 367 | + dest := filepath.Join(testdir, "target") 368 | + 369 | + buf := &bytes.Buffer{} 370 | + tw := tar.NewWriter(buf) 371 | + 372 | + const ( 373 | + srcName = "source" 374 | + content = "file contents" 375 | + ) 376 | + hdr := &tar.Header{ 377 | + Name: srcName, 378 | + Mode: 0666, 379 | + Size: int64(len(content)), 380 | + } 381 | + require.NoError(t, tw.WriteHeader(hdr)) 382 | + _, err = tw.Write([]byte(content)) 383 | + require.NoError(t, err) 384 | + tw.Close() 385 | + 386 | + require.NoError(t, untarAll(buf, filepath.Join(dest), srcName)) 387 | + cmpFileData(t, dest, content) 388 | } 389 | 390 | func createTmpFile(t *testing.T, filepath, data string) { 391 | @@ -955,20 +978,14 @@ func createTmpFile(t *testing.T, filepath, data string) { 392 | } 393 | 394 | func cmpFileData(t *testing.T, filePath, data string) { 395 | - f, err := os.Open(filePath) 396 | - if err != nil { 397 | - t.Fatalf("unexpected error: %v", err) 398 | - } 399 | + actual, err := ioutil.ReadFile(filePath) 400 | + require.NoError(t, err) 401 | + assert.EqualValues(t, data, actual) 402 | +} 403 | 404 | - defer f.Close() 405 | - buff := &bytes.Buffer{} 406 | - if _, err := io.Copy(buff, f); err != nil { 407 | - t.Fatal(err) 408 | - } 409 | - if err := f.Close(); err != nil { 410 | - t.Fatal(err) 411 | - } 412 | - if data != string(buff.Bytes()) { 413 | - t.Fatalf("expected: %s, saw: %s", data, string(buff.Bytes())) 414 | - } 415 | +type testWriter testing.T 416 | + 417 | +func (t *testWriter) Write(p []byte) (n int, err error) { 418 | + t.Logf(string(p)) 419 | + return len(p), nil 420 | } 421 | -------------------------------------------------------------------------------- /patches/CVE-2019-11249.1.12.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: M00nF1sh 3 | Date: Mon, 24 Jun 2019 11:16:00 -0700 4 | Subject: [PATCH 1/2] refactors to kubernetes CP command 5 | 6 | --- 7 | pkg/kubectl/cmd/cp.go | 5 +---- 8 | pkg/kubectl/cmd/cp_test.go | 36 ++++++++++++++++-------------------- 9 | 2 files changed, 17 insertions(+), 24 deletions(-) 10 | 11 | diff --git a/pkg/kubectl/cmd/cp.go b/pkg/kubectl/cmd/cp.go 12 | index f4c945499e8..b7ac616d050 100644 13 | --- a/pkg/kubectl/cmd/cp.go 14 | +++ b/pkg/kubectl/cmd/cp.go 15 | @@ -488,16 +488,13 @@ func linkJoin(base, link string) string { 16 | if filepath.IsAbs(link) { 17 | return link 18 | } 19 | - return filepath.Join(base, link) 20 | + return filepath.Join(filepath.Dir(base), link) 21 | } 22 | 23 | // isDestRelative returns true if dest is pointing outside the base directory, 24 | // false otherwise. 25 | func isDestRelative(base, dest string) bool { 26 | fullPath := dest 27 | - if !filepath.IsAbs(dest) { 28 | - fullPath = filepath.Join(base, dest) 29 | - } 30 | relative, err := filepath.Rel(base, fullPath) 31 | if err != nil { 32 | return false 33 | diff --git a/pkg/kubectl/cmd/cp_test.go b/pkg/kubectl/cmd/cp_test.go 34 | index 0615163bf4a..7a84b2a5f65 100644 35 | --- a/pkg/kubectl/cmd/cp_test.go 36 | +++ b/pkg/kubectl/cmd/cp_test.go 37 | @@ -197,12 +197,12 @@ func TestIsDestRelative(t *testing.T) { 38 | }{ 39 | { 40 | base: "/dir", 41 | - dest: "../link", 42 | + dest: "/dir/../link", 43 | relative: false, 44 | }, 45 | { 46 | base: "/dir", 47 | - dest: "../../link", 48 | + dest: "/dir/../../link", 49 | relative: false, 50 | }, 51 | { 52 | @@ -212,32 +212,27 @@ func TestIsDestRelative(t *testing.T) { 53 | }, 54 | { 55 | base: "/dir", 56 | - dest: "link", 57 | + dest: "/dir/link", 58 | relative: true, 59 | }, 60 | { 61 | base: "/dir", 62 | - dest: "int/file/link", 63 | + dest: "/dir/int/../link", 64 | relative: true, 65 | }, 66 | { 67 | - base: "/dir", 68 | - dest: "int/../link", 69 | + base: "dir", 70 | + dest: "dir/link", 71 | relative: true, 72 | }, 73 | { 74 | - base: "/dir", 75 | - dest: "/dir/link", 76 | + base: "dir", 77 | + dest: "dir/int/../link", 78 | relative: true, 79 | }, 80 | { 81 | - base: "/dir", 82 | - dest: "/dir/int/../link", 83 | - relative: true, 84 | - }, 85 | - { 86 | - base: "/dir", 87 | - dest: "/dir/../../link", 88 | + base: "dir", 89 | + dest: "dir/../../link", 90 | relative: false, 91 | }, 92 | } 93 | @@ -751,9 +746,10 @@ func TestUntar(t *testing.T) { 94 | } 95 | return expected + suffix 96 | } 97 | - mkBacktickExpectation := func(expected, suffix string) string { 98 | - dir, _ := filepath.Split(filepath.Clean(expected)) 99 | - if len(strings.Split(dir, string(os.PathSeparator))) <= 1 { 100 | + mkBacktickExpectation := func(path, expected, suffix string) string { 101 | + linkTarget := filepath.Join(backtick(path), "link-target") 102 | + baseDir := filepath.Join(testdir, dest) 103 | + if !isDestRelative(baseDir, linkJoin(filepath.Join(baseDir, path), linkTarget)) { 104 | return "" 105 | } 106 | return expected + suffix 107 | @@ -771,7 +767,7 @@ func TestUntar(t *testing.T) { 108 | }, file{ 109 | path: f.path + "-outerlink", 110 | linkTarget: filepath.Join(backtick(f.path), "link-target"), 111 | - expected: mkBacktickExpectation(f.expected, "-outerlink"), 112 | + expected: mkBacktickExpectation(f.path, f.expected, "-outerlink"), 113 | }, file{ 114 | path: f.path + "-outerlink-abs", 115 | linkTarget: filepath.Join(testdir, "link-target"), 116 | @@ -877,7 +873,7 @@ func TestUntar(t *testing.T) { 117 | 118 | // backtick returns a path to one directory up from the target 119 | func backtick(target string) string { 120 | - rel, _ := filepath.Rel(filepath.Dir(target), "../") 121 | + rel := filepath.Join(filepath.Dir(target), "../") 122 | return rel 123 | } 124 | 125 | 126 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 127 | From: Tim Allclair 128 | Date: Fri, 12 Jul 2019 11:53:10 -0700 129 | Subject: [PATCH 2/2] refactors to kubernetes cp command 130 | 131 | --- 132 | pkg/kubectl/cmd/cp.go | 34 +++++----- 133 | pkg/kubectl/cmd/cp_test.go | 129 ++++++++++++++++++++++--------------- 134 | 2 files changed, 92 insertions(+), 71 deletions(-) 135 | 136 | diff --git a/pkg/kubectl/cmd/cp.go b/pkg/kubectl/cmd/cp.go 137 | index b7ac616d050..a32edd7c396 100644 138 | --- a/pkg/kubectl/cmd/cp.go 139 | +++ b/pkg/kubectl/cmd/cp.go 140 | @@ -424,9 +424,14 @@ func (o *CopyOptions) untarAll(reader io.Reader, destDir, prefix string) error { 141 | 142 | // basic file information 143 | mode := header.FileInfo().Mode() 144 | - destFileName := path.Join(destDir, header.Name[len(prefix):]) 145 | - baseName := path.Dir(destFileName) 146 | + destFileName := filepath.Join(destDir, header.Name[len(prefix):]) 147 | 148 | + if !isDestRelative(destDir, destFileName) { 149 | + fmt.Fprintf(o.IOStreams.ErrOut, "warning: file %q is outside target destination, skipping\n", destFileName) 150 | + continue 151 | + } 152 | + 153 | + baseName := filepath.Dir(destFileName) 154 | if err := os.MkdirAll(baseName, 0755); err != nil { 155 | return err 156 | } 157 | @@ -440,15 +445,14 @@ func (o *CopyOptions) untarAll(reader io.Reader, destDir, prefix string) error { 158 | // We need to ensure that the destination file is always within boundries 159 | // of the destination directory. This prevents any kind of path traversal 160 | // from within tar archive. 161 | - dir, file := filepath.Split(destFileName) 162 | - evaledPath, err := filepath.EvalSymlinks(dir) 163 | + evaledPath, err := filepath.EvalSymlinks(baseName) 164 | if err != nil { 165 | return err 166 | } 167 | // For scrutiny we verify both the actual destination as well as we follow 168 | // all the links that might lead outside of the destination directory. 169 | - if !isDestRelative(destDir, destFileName) || !isDestRelative(destDir, filepath.Join(evaledPath, file)) { 170 | - fmt.Fprintf(o.IOStreams.ErrOut, "warning: link %q is pointing to %q which is outside target destination, skipping\n", destFileName, header.Linkname) 171 | + if !isDestRelative(destDir, filepath.Join(evaledPath, filepath.Base(destFileName))) { 172 | + fmt.Fprintf(o.IOStreams.ErrOut, "warning: file %q is outside target destination, skipping\n", destFileName) 173 | continue 174 | } 175 | 176 | @@ -457,7 +461,11 @@ func (o *CopyOptions) untarAll(reader io.Reader, destDir, prefix string) error { 177 | // We need to ensure that the link destination is always within boundries 178 | // of the destination directory. This prevents any kind of path traversal 179 | // from within tar archive. 180 | - if !isDestRelative(destDir, linkJoin(destFileName, linkname)) { 181 | + linkTarget := linkname 182 | + if !filepath.IsAbs(linkname) { 183 | + linkTarget = filepath.Join(evaledPath, linkname) 184 | + } 185 | + if !isDestRelative(destDir, linkTarget) { 186 | fmt.Fprintf(o.IOStreams.ErrOut, "warning: link %q is pointing to %q which is outside target destination, skipping\n", destFileName, header.Linkname) 187 | continue 188 | } 189 | @@ -482,20 +490,10 @@ func (o *CopyOptions) untarAll(reader io.Reader, destDir, prefix string) error { 190 | return nil 191 | } 192 | 193 | -// linkJoin joins base and link to get the final path to be created. 194 | -// It will consider whether link is an absolute path or not when returning result. 195 | -func linkJoin(base, link string) string { 196 | - if filepath.IsAbs(link) { 197 | - return link 198 | - } 199 | - return filepath.Join(filepath.Dir(base), link) 200 | -} 201 | - 202 | // isDestRelative returns true if dest is pointing outside the base directory, 203 | // false otherwise. 204 | func isDestRelative(base, dest string) bool { 205 | - fullPath := dest 206 | - relative, err := filepath.Rel(base, fullPath) 207 | + relative, err := filepath.Rel(base, dest) 208 | if err != nil { 209 | return false 210 | } 211 | diff --git a/pkg/kubectl/cmd/cp_test.go b/pkg/kubectl/cmd/cp_test.go 212 | index 7a84b2a5f65..e426b5cc4e8 100644 213 | --- a/pkg/kubectl/cmd/cp_test.go 214 | +++ b/pkg/kubectl/cmd/cp_test.go 215 | @@ -29,6 +29,7 @@ import ( 216 | "strings" 217 | "testing" 218 | 219 | + "github.com/stretchr/testify/assert" 220 | "github.com/stretchr/testify/require" 221 | 222 | "k8s.io/api/core/v1" 223 | @@ -704,9 +705,7 @@ func TestUntar(t *testing.T) { 224 | defer os.RemoveAll(testdir) 225 | t.Logf("Test base: %s", testdir) 226 | 227 | - const ( 228 | - dest = "base" 229 | - ) 230 | + basedir := filepath.Join(testdir, "base") 231 | 232 | type file struct { 233 | path string 234 | @@ -715,26 +714,26 @@ func TestUntar(t *testing.T) { 235 | } 236 | files := []file{{ 237 | // Absolute file within dest 238 | - path: filepath.Join(testdir, dest, "abs"), 239 | - expected: filepath.Join(testdir, dest, testdir, dest, "abs"), 240 | + path: filepath.Join(basedir, "abs"), 241 | + expected: filepath.Join(basedir, basedir, "abs"), 242 | }, { // Absolute file outside dest 243 | path: filepath.Join(testdir, "abs-out"), 244 | - expected: filepath.Join(testdir, dest, testdir, "abs-out"), 245 | + expected: filepath.Join(basedir, testdir, "abs-out"), 246 | }, { // Absolute nested file within dest 247 | - path: filepath.Join(testdir, dest, "nested/nest-abs"), 248 | - expected: filepath.Join(testdir, dest, testdir, dest, "nested/nest-abs"), 249 | + path: filepath.Join(basedir, "nested/nest-abs"), 250 | + expected: filepath.Join(basedir, basedir, "nested/nest-abs"), 251 | }, { // Absolute nested file outside dest 252 | - path: filepath.Join(testdir, dest, "nested/../../nest-abs-out"), 253 | - expected: filepath.Join(testdir, dest, testdir, "nest-abs-out"), 254 | + path: filepath.Join(basedir, "nested/../../nest-abs-out"), 255 | + expected: filepath.Join(basedir, testdir, "nest-abs-out"), 256 | }, { // Relative file inside dest 257 | path: "relative", 258 | - expected: filepath.Join(testdir, dest, "relative"), 259 | + expected: filepath.Join(basedir, "relative"), 260 | }, { // Relative file outside dest 261 | path: "../unrelative", 262 | expected: "", 263 | }, { // Nested relative file inside dest 264 | path: "nested/nest-rel", 265 | - expected: filepath.Join(testdir, dest, "nested/nest-rel"), 266 | + expected: filepath.Join(basedir, "nested/nest-rel"), 267 | }, { // Nested relative file outside dest 268 | path: "nested/../../nest-unrelative", 269 | expected: "", 270 | @@ -746,10 +745,11 @@ func TestUntar(t *testing.T) { 271 | } 272 | return expected + suffix 273 | } 274 | - mkBacktickExpectation := func(path, expected, suffix string) string { 275 | - linkTarget := filepath.Join(backtick(path), "link-target") 276 | - baseDir := filepath.Join(testdir, dest) 277 | - if !isDestRelative(baseDir, linkJoin(filepath.Join(baseDir, path), linkTarget)) { 278 | + mkBacklinkExpectation := func(expected, suffix string) string { 279 | + // "resolve" the back link relative to the expectation 280 | + targetDir := filepath.Dir(filepath.Dir(expected)) 281 | + // If the "resolved" target is not nested in basedir, it is escaping. 282 | + if !filepath.HasPrefix(targetDir, basedir) { 283 | return "" 284 | } 285 | return expected + suffix 286 | @@ -762,17 +762,27 @@ func TestUntar(t *testing.T) { 287 | expected: mkExpectation(f.expected, "-innerlink"), 288 | }, file{ 289 | path: f.path + "-innerlink-abs", 290 | - linkTarget: filepath.Join(testdir, dest, "link-target"), 291 | + linkTarget: filepath.Join(basedir, "link-target"), 292 | expected: mkExpectation(f.expected, "-innerlink-abs"), 293 | }, file{ 294 | - path: f.path + "-outerlink", 295 | - linkTarget: filepath.Join(backtick(f.path), "link-target"), 296 | - expected: mkBacktickExpectation(f.path, f.expected, "-outerlink"), 297 | + path: f.path + "-backlink", 298 | + linkTarget: filepath.Join("..", "link-target"), 299 | + expected: mkBacklinkExpectation(f.expected, "-backlink"), 300 | }, file{ 301 | path: f.path + "-outerlink-abs", 302 | linkTarget: filepath.Join(testdir, "link-target"), 303 | expected: "", 304 | }) 305 | + 306 | + if f.expected != "" { 307 | + // outerlink is the number of backticks to escape to testdir 308 | + outerlink, _ := filepath.Rel(f.expected, testdir) 309 | + links = append(links, file{ 310 | + path: f.path + "outerlink", 311 | + linkTarget: filepath.Join(outerlink, "link-target"), 312 | + expected: "", 313 | + }) 314 | + } 315 | } 316 | files = append(files, links...) 317 | 318 | @@ -781,11 +791,11 @@ func TestUntar(t *testing.T) { 319 | file{ 320 | path: "nested/again/back-link", 321 | linkTarget: "../../nested", 322 | - expected: filepath.Join(testdir, dest, "nested/again/back-link"), 323 | + expected: filepath.Join(basedir, "nested/again/back-link"), 324 | }, 325 | file{ 326 | path: "nested/again/back-link/../../../back-link-file", 327 | - expected: filepath.Join(testdir, dest, "back-link-file"), 328 | + expected: filepath.Join(basedir, "back-link-file"), 329 | }) 330 | 331 | // Test chaining back-tick symlinks. 332 | @@ -793,20 +803,11 @@ func TestUntar(t *testing.T) { 333 | file{ 334 | path: "nested/back-link-first", 335 | linkTarget: "../", 336 | - expected: filepath.Join(testdir, dest, "nested/back-link-first"), 337 | + expected: filepath.Join(basedir, "nested/back-link-first"), 338 | }, 339 | file{ 340 | path: "nested/back-link-first/back-link-second", 341 | linkTarget: "../", 342 | - expected: filepath.Join(testdir, dest, "back-link-second"), 343 | - }, 344 | - file{ 345 | - // This case is chaining together symlinks that step back, so that 346 | - // if you just look at the target relative to the path it appears 347 | - // inside the destination directory, but if you actually follow each 348 | - // step of the path you end up outside the destination directory. 349 | - path: "nested/back-link-first/back-link-second/back-link-term", 350 | - linkTarget: "", 351 | expected: "", 352 | }) 353 | 354 | @@ -846,9 +847,11 @@ func TestUntar(t *testing.T) { 355 | } 356 | tw.Close() 357 | 358 | - opts := NewCopyOptions(genericclioptions.NewTestIOStreamsDiscard()) 359 | + // Capture warnings to stderr for debugging. 360 | + output := (*testWriter)(t) 361 | + opts := NewCopyOptions(genericclioptions.IOStreams{In: &bytes.Buffer{}, Out: output, ErrOut: output}) 362 | 363 | - require.NoError(t, opts.untarAll(buf, filepath.Join(testdir, dest), "")) 364 | + require.NoError(t, opts.untarAll(buf, filepath.Join(basedir), "")) 365 | 366 | filepath.Walk(testdir, func(path string, info os.FileInfo, err error) error { 367 | if err != nil { 368 | @@ -871,10 +874,36 @@ func TestUntar(t *testing.T) { 369 | } 370 | } 371 | 372 | -// backtick returns a path to one directory up from the target 373 | -func backtick(target string) string { 374 | - rel := filepath.Join(filepath.Dir(target), "../") 375 | - return rel 376 | +func TestUntar_SingleFile(t *testing.T) { 377 | + testdir, err := ioutil.TempDir("", "test-untar") 378 | + require.NoError(t, err) 379 | + defer os.RemoveAll(testdir) 380 | + 381 | + dest := filepath.Join(testdir, "target") 382 | + 383 | + buf := &bytes.Buffer{} 384 | + tw := tar.NewWriter(buf) 385 | + 386 | + const ( 387 | + srcName = "source" 388 | + content = "file contents" 389 | + ) 390 | + hdr := &tar.Header{ 391 | + Name: srcName, 392 | + Mode: 0666, 393 | + Size: int64(len(content)), 394 | + } 395 | + require.NoError(t, tw.WriteHeader(hdr)) 396 | + _, err = tw.Write([]byte(content)) 397 | + require.NoError(t, err) 398 | + tw.Close() 399 | + 400 | + // Capture warnings to stderr for debugging. 401 | + output := (*testWriter)(t) 402 | + opts := NewCopyOptions(genericclioptions.IOStreams{In: &bytes.Buffer{}, Out: output, ErrOut: output}) 403 | + 404 | + require.NoError(t, opts.untarAll(buf, filepath.Join(dest), srcName)) 405 | + cmpFileData(t, dest, content) 406 | } 407 | 408 | func createTmpFile(t *testing.T, filepath, data string) { 409 | @@ -892,20 +921,14 @@ func createTmpFile(t *testing.T, filepath, data string) { 410 | } 411 | 412 | func cmpFileData(t *testing.T, filePath, data string) { 413 | - f, err := os.Open(filePath) 414 | - if err != nil { 415 | - t.Fatalf("unexpected error: %v", err) 416 | - } 417 | + actual, err := ioutil.ReadFile(filePath) 418 | + require.NoError(t, err) 419 | + assert.EqualValues(t, data, actual) 420 | +} 421 | 422 | - defer f.Close() 423 | - buff := &bytes.Buffer{} 424 | - if _, err := io.Copy(buff, f); err != nil { 425 | - t.Fatal(err) 426 | - } 427 | - if err := f.Close(); err != nil { 428 | - t.Fatal(err) 429 | - } 430 | - if data != string(buff.Bytes()) { 431 | - t.Fatalf("expected: %s, saw: %s", data, string(buff.Bytes())) 432 | - } 433 | +type testWriter testing.T 434 | + 435 | +func (t *testWriter) Write(p []byte) (n int, err error) { 436 | + t.Logf(string(p)) 437 | + return len(p), nil 438 | } 439 | -------------------------------------------------------------------------------- /patches/CVE-2019-11251.1.10.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Tim Allclair 3 | Date: Thu, 5 Sep 2019 11:47:43 -0700 4 | Subject: [PATCH] Reorder symlinks to prevent path escapes 5 | 6 | --- 7 | pkg/kubectl/cmd/cp.go | 29 ++++---- 8 | pkg/kubectl/cmd/cp_test.go | 148 ++++++++++++++++++++++--------------- 9 | 2 files changed, 105 insertions(+), 72 deletions(-) 10 | 11 | diff --git a/pkg/kubectl/cmd/cp.go b/pkg/kubectl/cmd/cp.go 12 | index 228ce3f7368..23e82e2849d 100644 13 | --- a/pkg/kubectl/cmd/cp.go 14 | +++ b/pkg/kubectl/cmd/cp.go 15 | @@ -346,6 +346,7 @@ func clean(fileName string) string { 16 | func untarAll(reader io.Reader, destDir, prefix string) error { 17 | // TODO: use compression here? 18 | tarReader := tar.NewReader(reader) 19 | + symlinks := map[string]string{} // map of link -> destination 20 | for { 21 | header, err := tarReader.Next() 22 | if err != nil { 23 | @@ -399,21 +400,10 @@ func untarAll(reader io.Reader, destDir, prefix string) error { 24 | } 25 | 26 | if mode&os.ModeSymlink != 0 { 27 | - linkname := header.Linkname 28 | - // We need to ensure that the link destination is always within boundries 29 | - // of the destination directory. This prevents any kind of path traversal 30 | - // from within tar archive. 31 | - linkTarget := linkname 32 | - if !filepath.IsAbs(linkname) { 33 | - linkTarget = filepath.Join(evaledPath, linkname) 34 | - } 35 | - if !isDestRelative(destDir, linkTarget) { 36 | - fmt.Fprintf(os.Stderr, "warning: link %q is pointing to %q which is outside target destination, skipping\n", destFileName, header.Linkname) 37 | - continue 38 | - } 39 | - if err := os.Symlink(linkname, destFileName); err != nil { 40 | - return err 41 | + if _, exists := symlinks[destFileName]; exists { 42 | + return fmt.Errorf("duplicate symlink: %q", destFileName) 43 | } 44 | + symlinks[destFileName] = header.Linkname 45 | } else { 46 | outFile, err := os.Create(destFileName) 47 | if err != nil { 48 | @@ -429,6 +419,17 @@ func untarAll(reader io.Reader, destDir, prefix string) error { 49 | } 50 | } 51 | 52 | + // Create symlinks after all regular files have been written. 53 | + // Ordering this way prevents writing data outside the destination directory through path 54 | + // traversals. 55 | + // Symlink chaining is prevented due to the directory tree being established (MkdirAll) before 56 | + // creating any symlinks. 57 | + for newname, oldname := range symlinks { 58 | + if err := os.Symlink(oldname, newname); err != nil { 59 | + return err 60 | + } 61 | + } 62 | + 63 | return nil 64 | } 65 | 66 | diff --git a/pkg/kubectl/cmd/cp_test.go b/pkg/kubectl/cmd/cp_test.go 67 | index 6795499f9e1..672c99cf0d6 100644 68 | --- a/pkg/kubectl/cmd/cp_test.go 69 | +++ b/pkg/kubectl/cmd/cp_test.go 70 | @@ -299,13 +299,11 @@ func TestTarUntar(t *testing.T) { 71 | { 72 | name: "tricky_relative", 73 | data: path.Join(dir3, "xyz"), 74 | - omitted: true, 75 | fileType: SymLink, 76 | }, 77 | { 78 | name: "absolute_path", 79 | data: "/tmp/gakki", 80 | - omitted: true, 81 | fileType: SymLink, 82 | }, 83 | } 84 | @@ -764,6 +762,12 @@ func TestCopyToPod(t *testing.T) { 85 | } 86 | } 87 | 88 | +type testFile struct { 89 | + path string 90 | + linkTarget string // For link types 91 | + expected string // Expect to find the file here (or not, if empty) 92 | +} 93 | + 94 | func TestUntar(t *testing.T) { 95 | testdir, err := ioutil.TempDir("", "test-untar") 96 | require.NoError(t, err) 97 | @@ -772,12 +776,7 @@ func TestUntar(t *testing.T) { 98 | 99 | basedir := filepath.Join(testdir, "base") 100 | 101 | - type file struct { 102 | - path string 103 | - linkTarget string // For link types 104 | - expected string // Expect to find the file here (or not, if empty) 105 | - } 106 | - files := []file{{ 107 | + files := []testFile{{ 108 | // Absolute file within dest 109 | path: filepath.Join(basedir, "abs"), 110 | expected: filepath.Join(basedir, basedir, "abs"), 111 | @@ -810,42 +809,33 @@ func TestUntar(t *testing.T) { 112 | } 113 | return expected + suffix 114 | } 115 | - mkBacklinkExpectation := func(expected, suffix string) string { 116 | - // "resolve" the back link relative to the expectation 117 | - targetDir := filepath.Dir(filepath.Dir(expected)) 118 | - // If the "resolved" target is not nested in basedir, it is escaping. 119 | - if !filepath.HasPrefix(targetDir, basedir) { 120 | - return "" 121 | - } 122 | - return expected + suffix 123 | - } 124 | - links := []file{} 125 | + links := []testFile{} 126 | for _, f := range files { 127 | - links = append(links, file{ 128 | + links = append(links, testFile{ 129 | path: f.path + "-innerlink", 130 | linkTarget: "link-target", 131 | expected: mkExpectation(f.expected, "-innerlink"), 132 | - }, file{ 133 | + }, testFile{ 134 | path: f.path + "-innerlink-abs", 135 | linkTarget: filepath.Join(basedir, "link-target"), 136 | expected: mkExpectation(f.expected, "-innerlink-abs"), 137 | - }, file{ 138 | + }, testFile{ 139 | path: f.path + "-backlink", 140 | linkTarget: filepath.Join("..", "link-target"), 141 | - expected: mkBacklinkExpectation(f.expected, "-backlink"), 142 | - }, file{ 143 | + expected: mkExpectation(f.expected, "-backlink"), 144 | + }, testFile{ 145 | path: f.path + "-outerlink-abs", 146 | linkTarget: filepath.Join(testdir, "link-target"), 147 | - expected: "", 148 | + expected: mkExpectation(f.expected, "-outerlink-abs"), 149 | }) 150 | 151 | if f.expected != "" { 152 | // outerlink is the number of backticks to escape to testdir 153 | outerlink, _ := filepath.Rel(f.expected, testdir) 154 | - links = append(links, file{ 155 | - path: f.path + "outerlink", 156 | + links = append(links, testFile{ 157 | + path: f.path + "-outerlink", 158 | linkTarget: filepath.Join(outerlink, "link-target"), 159 | - expected: "", 160 | + expected: mkExpectation(f.expected, "-outerlink"), 161 | }) 162 | } 163 | } 164 | @@ -853,42 +843,104 @@ func TestUntar(t *testing.T) { 165 | 166 | // Test back-tick escaping through a symlink. 167 | files = append(files, 168 | - file{ 169 | + testFile{ 170 | path: "nested/again/back-link", 171 | linkTarget: "../../nested", 172 | expected: filepath.Join(basedir, "nested/again/back-link"), 173 | }, 174 | - file{ 175 | + testFile{ 176 | path: "nested/again/back-link/../../../back-link-file", 177 | expected: filepath.Join(basedir, "back-link-file"), 178 | }) 179 | 180 | // Test chaining back-tick symlinks. 181 | files = append(files, 182 | - file{ 183 | + testFile{ 184 | path: "nested/back-link-first", 185 | linkTarget: "../", 186 | expected: filepath.Join(basedir, "nested/back-link-first"), 187 | }, 188 | - file{ 189 | - path: "nested/back-link-first/back-link-second", 190 | - linkTarget: "../", 191 | - expected: "", 192 | + testFile{ 193 | + path: "nested/back-link-second", 194 | + linkTarget: "back-link-first/..", 195 | + expected: filepath.Join(basedir, "nested/back-link-second"), 196 | }) 197 | 198 | files = append(files, 199 | - file{ // Relative directory path with terminating / 200 | + testFile{ // Relative directory path with terminating / 201 | path: "direct/dir/", 202 | expected: "", 203 | }) 204 | 205 | - buf := &bytes.Buffer{} 206 | - tw := tar.NewWriter(buf) 207 | + buf := makeTestTar(t, files) 208 | + 209 | + require.NoError(t, untarAll(buf, filepath.Join(basedir), "")) 210 | + 211 | expectations := map[string]bool{} 212 | for _, f := range files { 213 | if f.expected != "" { 214 | expectations[f.expected] = false 215 | } 216 | + } 217 | + filepath.Walk(testdir, func(path string, info os.FileInfo, err error) error { 218 | + if err != nil { 219 | + return err 220 | + } 221 | + if info.IsDir() { 222 | + return nil // Ignore directories. 223 | + } 224 | + if _, ok := expectations[path]; !ok { 225 | + t.Errorf("Unexpected file at %s", path) 226 | + } else { 227 | + expectations[path] = true 228 | + } 229 | + return nil 230 | + }) 231 | + for path, found := range expectations { 232 | + if !found { 233 | + t.Errorf("Missing expected file %s", path) 234 | + } 235 | + } 236 | +} 237 | + 238 | +func TestUntar_NestedSymlinks(t *testing.T) { 239 | + testdir, err := ioutil.TempDir("", "test-untar-nested") 240 | + require.NoError(t, err) 241 | + defer os.RemoveAll(testdir) 242 | + t.Logf("Test base: %s", testdir) 243 | + 244 | + basedir := filepath.Join(testdir, "base") 245 | + 246 | + // Test chaining back-tick symlinks. 247 | + backLinkFirst := testFile{ 248 | + path: "nested/back-link-first", 249 | + linkTarget: "../", 250 | + expected: filepath.Join(basedir, "nested/back-link-first"), 251 | + } 252 | + files := []testFile{backLinkFirst, { 253 | + path: "nested/back-link-first/back-link-second", 254 | + linkTarget: "../", 255 | + expected: "", 256 | + }} 257 | + 258 | + buf := makeTestTar(t, files) 259 | + 260 | + // Expect untarAll to fail. The second link will trigger a directory to be created at 261 | + // "nested/back-link-first", which should trigger a file exists error when the back-link-first 262 | + // symlink is created. 263 | + expectedErr := os.LinkError{ 264 | + Op: "symlink", 265 | + Old: backLinkFirst.linkTarget, 266 | + New: backLinkFirst.expected, 267 | + Err: fmt.Errorf("file exists")} 268 | + actualErr := untarAll(buf, filepath.Join(basedir), "") 269 | + assert.EqualError(t, actualErr, expectedErr.Error()) 270 | +} 271 | + 272 | +func makeTestTar(t *testing.T, files []testFile) *bytes.Buffer { 273 | + buf := &bytes.Buffer{} 274 | + tw := tar.NewWriter(buf) 275 | + for _, f := range files { 276 | if f.linkTarget == "" { 277 | hdr := &tar.Header{ 278 | Name: f.path, 279 | @@ -912,27 +964,7 @@ func TestUntar(t *testing.T) { 280 | } 281 | tw.Close() 282 | 283 | - require.NoError(t, untarAll(buf, filepath.Join(testdir, dest), "")) 284 | - 285 | - filepath.Walk(testdir, func(path string, info os.FileInfo, err error) error { 286 | - if err != nil { 287 | - return err 288 | - } 289 | - if info.IsDir() { 290 | - return nil // Ignore directories. 291 | - } 292 | - if _, ok := expectations[path]; !ok { 293 | - t.Errorf("Unexpected file at %s", path) 294 | - } else { 295 | - expectations[path] = true 296 | - } 297 | - return nil 298 | - }) 299 | - for path, found := range expectations { 300 | - if !found { 301 | - t.Errorf("Missing expected file %s", path) 302 | - } 303 | - } 304 | + return buf 305 | } 306 | 307 | func TestUntar_SingleFile(t *testing.T) { 308 | -------------------------------------------------------------------------------- /patches/CVE-2020-8552.1.11.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Han Kang 3 | Date: Wed, 29 Jan 2020 13:39:59 -0800 4 | Subject: [PATCH] blank out value for unbounded client label 5 | 6 | Change-Id: If179557706cbecab0cf16417c8cf2c5536b02559 7 | --- 8 | staging/src/k8s.io/apiserver/pkg/endpoints/metrics/BUILD | 1 - 9 | staging/src/k8s.io/apiserver/pkg/endpoints/metrics/metrics.go | 4 ++-- 10 | 2 files changed, 2 insertions(+), 3 deletions(-) 11 | 12 | diff --git a/staging/src/k8s.io/apiserver/pkg/endpoints/metrics/BUILD b/staging/src/k8s.io/apiserver/pkg/endpoints/metrics/BUILD 13 | index 6aef95e2dc8..e2dce55ef17 100644 14 | --- a/staging/src/k8s.io/apiserver/pkg/endpoints/metrics/BUILD 15 | +++ b/staging/src/k8s.io/apiserver/pkg/endpoints/metrics/BUILD 16 | @@ -19,7 +19,6 @@ go_library( 17 | deps = [ 18 | "//vendor/github.com/emicklei/go-restful:go_default_library", 19 | "//vendor/github.com/prometheus/client_golang/prometheus:go_default_library", 20 | - "//vendor/k8s.io/apimachinery/pkg/util/net:go_default_library", 21 | "//vendor/k8s.io/apiserver/pkg/endpoints/request:go_default_library", 22 | ], 23 | ) 24 | diff --git a/staging/src/k8s.io/apiserver/pkg/endpoints/metrics/metrics.go b/staging/src/k8s.io/apiserver/pkg/endpoints/metrics/metrics.go 25 | index 516452e160b..310d8e1c8a5 100644 26 | --- a/staging/src/k8s.io/apiserver/pkg/endpoints/metrics/metrics.go 27 | +++ b/staging/src/k8s.io/apiserver/pkg/endpoints/metrics/metrics.go 28 | @@ -26,7 +26,6 @@ import ( 29 | "sync" 30 | "time" 31 | 32 | - utilnet "k8s.io/apimachinery/pkg/util/net" 33 | "k8s.io/apiserver/pkg/endpoints/request" 34 | 35 | "github.com/emicklei/go-restful" 36 | @@ -192,7 +191,8 @@ func RecordLongRunning(req *http.Request, requestInfo *request.RequestInfo, fn f 37 | // a request. verb must be uppercase to be backwards compatible with existing monitoring tooling. 38 | func MonitorRequest(req *http.Request, verb, resource, subresource, scope, contentType string, httpCode, respSize int, elapsed time.Duration) { 39 | reportedVerb := cleanVerb(verb, req) 40 | - client := cleanUserAgent(utilnet.GetHTTPClient(req)) 41 | + // blank out client string here, in order to avoid cardinality issues 42 | + client := "" 43 | elapsedMicroseconds := float64(elapsed / time.Microsecond) 44 | requestCounter.WithLabelValues(reportedVerb, resource, subresource, scope, client, contentType, codeToString(httpCode)).Inc() 45 | requestLatencies.WithLabelValues(reportedVerb, resource, subresource, scope).Observe(elapsedMicroseconds) 46 | -------------------------------------------------------------------------------- /patches/CVE-2020-8552.1.13.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Han Kang 3 | Date: Wed, 29 Jan 2020 13:39:59 -0800 4 | Subject: [PATCH] blank out value for unbounded client label 5 | 6 | Change-Id: If179557706cbecab0cf16417c8cf2c5536b02559 7 | --- 8 | staging/src/k8s.io/apiserver/pkg/endpoints/metrics/BUILD | 1 - 9 | staging/src/k8s.io/apiserver/pkg/endpoints/metrics/metrics.go | 4 ++-- 10 | 2 files changed, 2 insertions(+), 3 deletions(-) 11 | 12 | diff --git a/staging/src/k8s.io/apiserver/pkg/endpoints/metrics/BUILD b/staging/src/k8s.io/apiserver/pkg/endpoints/metrics/BUILD 13 | index ea44cdc05e8..57442696162 100644 14 | --- a/staging/src/k8s.io/apiserver/pkg/endpoints/metrics/BUILD 15 | +++ b/staging/src/k8s.io/apiserver/pkg/endpoints/metrics/BUILD 16 | @@ -18,7 +18,6 @@ go_library( 17 | importmap = "k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/endpoints/metrics", 18 | importpath = "k8s.io/apiserver/pkg/endpoints/metrics", 19 | deps = [ 20 | - "//staging/src/k8s.io/apimachinery/pkg/util/net:go_default_library", 21 | "//staging/src/k8s.io/apiserver/pkg/endpoints/request:go_default_library", 22 | "//vendor/github.com/emicklei/go-restful:go_default_library", 23 | "//vendor/github.com/prometheus/client_golang/prometheus:go_default_library", 24 | diff --git a/staging/src/k8s.io/apiserver/pkg/endpoints/metrics/metrics.go b/staging/src/k8s.io/apiserver/pkg/endpoints/metrics/metrics.go 25 | index ae16d43bb1e..affb8f35bb7 100644 26 | --- a/staging/src/k8s.io/apiserver/pkg/endpoints/metrics/metrics.go 27 | +++ b/staging/src/k8s.io/apiserver/pkg/endpoints/metrics/metrics.go 28 | @@ -26,7 +26,6 @@ import ( 29 | "sync" 30 | "time" 31 | 32 | - utilnet "k8s.io/apimachinery/pkg/util/net" 33 | "k8s.io/apiserver/pkg/endpoints/request" 34 | 35 | "github.com/emicklei/go-restful" 36 | @@ -192,7 +191,8 @@ func RecordLongRunning(req *http.Request, requestInfo *request.RequestInfo, fn f 37 | // a request. verb must be uppercase to be backwards compatible with existing monitoring tooling. 38 | func MonitorRequest(req *http.Request, verb, resource, subresource, scope, contentType string, httpCode, respSize int, elapsed time.Duration) { 39 | reportedVerb := cleanVerb(verb, req) 40 | - client := cleanUserAgent(utilnet.GetHTTPClient(req)) 41 | + // blank out client string here, in order to avoid cardinality issues 42 | + client := "" 43 | elapsedMicroseconds := float64(elapsed / time.Microsecond) 44 | requestCounter.WithLabelValues(reportedVerb, resource, subresource, scope, client, contentType, codeToString(httpCode)).Inc() 45 | requestLatencies.WithLabelValues(reportedVerb, resource, subresource, scope).Observe(elapsedMicroseconds) 46 | -------------------------------------------------------------------------------- /patches/CVE-2020-8552.1.14.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Han Kang 3 | Date: Wed, 29 Jan 2020 13:39:59 -0800 4 | Subject: [PATCH] blank out value for unbounded client label 5 | 6 | Change-Id: If179557706cbecab0cf16417c8cf2c5536b02559 7 | --- 8 | staging/src/k8s.io/apiserver/pkg/endpoints/metrics/BUILD | 1 - 9 | staging/src/k8s.io/apiserver/pkg/endpoints/metrics/metrics.go | 4 ++-- 10 | 2 files changed, 2 insertions(+), 3 deletions(-) 11 | 12 | diff --git a/staging/src/k8s.io/apiserver/pkg/endpoints/metrics/BUILD b/staging/src/k8s.io/apiserver/pkg/endpoints/metrics/BUILD 13 | index 4df68923804..39eb0690ebc 100644 14 | --- a/staging/src/k8s.io/apiserver/pkg/endpoints/metrics/BUILD 15 | +++ b/staging/src/k8s.io/apiserver/pkg/endpoints/metrics/BUILD 16 | @@ -20,7 +20,6 @@ go_library( 17 | deps = [ 18 | "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/validation:go_default_library", 19 | "//staging/src/k8s.io/apimachinery/pkg/types:go_default_library", 20 | - "//staging/src/k8s.io/apimachinery/pkg/util/net:go_default_library", 21 | "//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library", 22 | "//staging/src/k8s.io/apiserver/pkg/endpoints/request:go_default_library", 23 | "//staging/src/k8s.io/apiserver/pkg/features:go_default_library", 24 | diff --git a/staging/src/k8s.io/apiserver/pkg/endpoints/metrics/metrics.go b/staging/src/k8s.io/apiserver/pkg/endpoints/metrics/metrics.go 25 | index 50058503889..8b51456d503 100644 26 | --- a/staging/src/k8s.io/apiserver/pkg/endpoints/metrics/metrics.go 27 | +++ b/staging/src/k8s.io/apiserver/pkg/endpoints/metrics/metrics.go 28 | @@ -28,7 +28,6 @@ import ( 29 | 30 | "k8s.io/apimachinery/pkg/apis/meta/v1/validation" 31 | "k8s.io/apimachinery/pkg/types" 32 | - utilnet "k8s.io/apimachinery/pkg/util/net" 33 | utilsets "k8s.io/apimachinery/pkg/util/sets" 34 | "k8s.io/apiserver/pkg/endpoints/request" 35 | "k8s.io/apiserver/pkg/features" 36 | @@ -247,7 +246,8 @@ func RecordLongRunning(req *http.Request, requestInfo *request.RequestInfo, comp 37 | func MonitorRequest(req *http.Request, verb, group, version, resource, subresource, scope, component, contentType string, httpCode, respSize int, elapsed time.Duration) { 38 | reportedVerb := cleanVerb(verb, req) 39 | dryRun := cleanDryRun(req.URL.Query()["dryRun"]) 40 | - client := cleanUserAgent(utilnet.GetHTTPClient(req)) 41 | + // blank out client string here, in order to avoid cardinality issues 42 | + client := "" 43 | elapsedMicroseconds := float64(elapsed / time.Microsecond) 44 | elapsedSeconds := elapsed.Seconds() 45 | requestCounter.WithLabelValues(reportedVerb, dryRun, group, version, resource, subresource, scope, component, client, contentType, codeToString(httpCode)).Inc() 46 | -------------------------------------------------------------------------------- /patches/CVE-2020-8555.1.14.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Michelle Au 3 | Date: Thu, 2 Apr 2020 13:47:56 -0700 4 | Subject: [PATCH] Clean up event messages for errors. 5 | 6 | Change-Id: Ib70b50e676b917c4d976f32ee7a19f8fc63b6bc6 7 | --- 8 | pkg/volume/glusterfs/glusterfs.go | 35 ++++++++----- 9 | pkg/volume/quobyte/quobyte.go | 13 ++++- 10 | pkg/volume/scaleio/sio_client.go | 71 ++++++++++++++++++-------- 11 | pkg/volume/storageos/storageos_util.go | 12 +++-- 12 | 4 files changed, 92 insertions(+), 39 deletions(-) 13 | 14 | diff --git a/pkg/volume/glusterfs/glusterfs.go b/pkg/volume/glusterfs/glusterfs.go 15 | index d357d0aec92..19a9fecd6e0 100644 16 | --- a/pkg/volume/glusterfs/glusterfs.go 17 | +++ b/pkg/volume/glusterfs/glusterfs.go 18 | @@ -28,7 +28,7 @@ import ( 19 | 20 | gcli "github.com/heketi/heketi/client/api/go-client" 21 | gapi "github.com/heketi/heketi/pkg/glusterfs/api" 22 | - "k8s.io/api/core/v1" 23 | + v1 "k8s.io/api/core/v1" 24 | "k8s.io/apimachinery/pkg/api/errors" 25 | "k8s.io/apimachinery/pkg/api/resource" 26 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 27 | @@ -702,8 +702,9 @@ func (d *glusterfsVolumeDeleter) Delete() error { 28 | } 29 | err = cli.VolumeDelete(volumeID) 30 | if err != nil { 31 | - klog.Errorf("failed to delete volume %s: %v", volumeName, err) 32 | - return err 33 | + // don't log error details from client calls in events 34 | + klog.V(4).Infof("failed to delete volume %s: %v", volumeName, err) 35 | + return fmt.Errorf("failed to delete volume: see kube-controller-manager.log for details") 36 | } 37 | klog.V(2).Infof("volume %s deleted successfully", volumeName) 38 | 39 | @@ -848,8 +849,9 @@ func (p *glusterfsVolumeProvisioner) CreateVolume(gid int) (r *v1.GlusterfsPersi 40 | volumeReq := &gapi.VolumeCreateRequest{Size: sz, Name: customVolumeName, Clusters: clusterIDs, Gid: gid64, Durability: p.volumeType, GlusterVolumeOptions: p.volumeOptions, Snapshot: snaps} 41 | volume, err := cli.VolumeCreate(volumeReq) 42 | if err != nil { 43 | - klog.Errorf("failed to create volume: %v", err) 44 | - return nil, 0, "", fmt.Errorf("failed to create volume: %v", err) 45 | + // don't log error details from client calls in events 46 | + klog.V(4).Infof("failed to create volume: %v", err) 47 | + return nil, 0, "", fmt.Errorf("failed to create volume: see kube-controller-manager.log for details") 48 | } 49 | klog.V(1).Infof("volume with size %d and name %s created", volume.Size, volume.Name) 50 | volID = volume.Id 51 | @@ -870,7 +872,8 @@ func (p *glusterfsVolumeProvisioner) CreateVolume(gid int) (r *v1.GlusterfsPersi 52 | klog.Errorf("failed to create endpoint/service %v/%v: %v", epNamespace, epServiceName, err) 53 | deleteErr := cli.VolumeDelete(volume.Id) 54 | if deleteErr != nil { 55 | - klog.Errorf("failed to delete volume: %v, manual deletion of the volume required", deleteErr) 56 | + // don't log error details from client calls in events 57 | + klog.V(4).Infof("failed to delete volume: %v, manual deletion of the volume required", deleteErr) 58 | } 59 | return nil, 0, "", fmt.Errorf("failed to create endpoint/service %v/%v: %v", epNamespace, epServiceName, err) 60 | } 61 | @@ -982,8 +985,9 @@ func parseSecret(namespace, secretName string, kubeClient clientset.Interface) ( 62 | func getClusterNodes(cli *gcli.Client, cluster string) (dynamicHostIps []string, err error) { 63 | clusterinfo, err := cli.ClusterInfo(cluster) 64 | if err != nil { 65 | - klog.Errorf("failed to get cluster details: %v", err) 66 | - return nil, fmt.Errorf("failed to get cluster details: %v", err) 67 | + // don't log error details from client calls in events 68 | + klog.V(4).Infof("failed to get cluster details: %v", err) 69 | + return nil, fmt.Errorf("failed to get cluster details: see kube-controller-manager.log for details") 70 | } 71 | 72 | // For the dynamically provisioned volume, we gather the list of node IPs 73 | @@ -992,8 +996,9 @@ func getClusterNodes(cli *gcli.Client, cluster string) (dynamicHostIps []string, 74 | for _, node := range clusterinfo.Nodes { 75 | nodeInfo, err := cli.NodeInfo(string(node)) 76 | if err != nil { 77 | - klog.Errorf("failed to get host ipaddress: %v", err) 78 | - return nil, fmt.Errorf("failed to get host ipaddress: %v", err) 79 | + // don't log error details from client calls in events 80 | + klog.V(4).Infof("failed to get host ipaddress: %v", err) 81 | + return nil, fmt.Errorf("failed to get host ipaddress: see kube-controller-manager.log for details") 82 | } 83 | ipaddr := dstrings.Join(nodeInfo.NodeAddRequest.Hostnames.Storage, "") 84 | dynamicHostIps = append(dynamicHostIps, ipaddr) 85 | @@ -1250,8 +1255,9 @@ func (plugin *glusterfsPlugin) ExpandVolumeDevice(spec *volume.Spec, newSize res 86 | //Check the existing volume size 87 | currentVolumeInfo, err := cli.VolumeInfo(volumeID) 88 | if err != nil { 89 | - klog.Errorf("error when fetching details of volume %s: %v", volumeName, err) 90 | - return oldSize, err 91 | + // don't log error details from client calls in events 92 | + klog.V(4).Infof("error when fetching details of volume %s: %v", volumeName, err) 93 | + return oldSize, fmt.Errorf("failed to get volume info %s: see kube-controller-manager.log for details", volumeName) 94 | } 95 | 96 | if int64(currentVolumeInfo.Size) >= requestGiB { 97 | @@ -1264,8 +1270,9 @@ func (plugin *glusterfsPlugin) ExpandVolumeDevice(spec *volume.Spec, newSize res 98 | // Expand the volume 99 | volumeInfoRes, err := cli.VolumeExpand(volumeID, volumeExpandReq) 100 | if err != nil { 101 | - klog.Errorf("failed to expand volume %s: %v", volumeName, err) 102 | - return oldSize, err 103 | + // don't log error details from client calls in events 104 | + klog.V(4).Infof("failed to expand volume %s: %v", volumeName, err) 105 | + return oldSize, fmt.Errorf("failed to expand volume: see kube-controller-manager.log for details") 106 | } 107 | 108 | klog.V(2).Infof("volume %s expanded to new size %d successfully", volumeName, volumeInfoRes.Size) 109 | diff --git a/pkg/volume/quobyte/quobyte.go b/pkg/volume/quobyte/quobyte.go 110 | index 087bdaecbf0..7aa277a1562 100644 111 | --- a/pkg/volume/quobyte/quobyte.go 112 | +++ b/pkg/volume/quobyte/quobyte.go 113 | @@ -17,6 +17,7 @@ limitations under the License. 114 | package quobyte 115 | 116 | import ( 117 | + "errors" 118 | "fmt" 119 | "os" 120 | "path" 121 | @@ -416,7 +417,9 @@ func (provisioner *quobyteVolumeProvisioner) Provision(selectedNode *v1.Node, al 122 | 123 | vol, sizeGB, err := manager.createVolume(provisioner, createQuota) 124 | if err != nil { 125 | - return nil, err 126 | + // don't log error details from client calls in events 127 | + klog.V(4).Infof("CreateVolume failed: %v", err) 128 | + return nil, errors.New("CreateVolume failed: see kube-controller-manager.log for details") 129 | } 130 | pv := new(v1.PersistentVolume) 131 | metav1.SetMetaDataAnnotation(&pv.ObjectMeta, util.VolumeDynamicallyCreatedByKey, "quobyte-dynamic-provisioner") 132 | @@ -451,7 +454,13 @@ func (deleter *quobyteVolumeDeleter) Delete() error { 133 | manager := &quobyteVolumeManager{ 134 | config: cfg, 135 | } 136 | - return manager.deleteVolume(deleter) 137 | + err = manager.deleteVolume(deleter) 138 | + if err != nil { 139 | + // don't log error details from client calls in events 140 | + klog.V(4).Infof("DeleteVolume failed: %v", err) 141 | + return errors.New("DeleteVolume failed: see kube-controller-manager.log for details") 142 | + } 143 | + return nil 144 | } 145 | 146 | // Parse API configuration (url, username and password) out of class.Parameters. 147 | diff --git a/pkg/volume/scaleio/sio_client.go b/pkg/volume/scaleio/sio_client.go 148 | index 2c7041f478e..bfba897cde9 100644 149 | --- a/pkg/volume/scaleio/sio_client.go 150 | +++ b/pkg/volume/scaleio/sio_client.go 151 | @@ -127,8 +127,9 @@ func (c *sioClient) init() error { 152 | Username: c.username, 153 | Password: c.password}, 154 | ); err != nil { 155 | - klog.Error(log("client authentication failed: %v", err)) 156 | - return err 157 | + // don't log error details from client calls in events 158 | + klog.V(4).Infof(log("client authentication failed: %v", err)) 159 | + return errors.New("client authentication failed") 160 | } 161 | 162 | // retrieve system 163 | @@ -215,8 +216,9 @@ func (c *sioClient) CreateVolume(name string, sizeGB int64) (*siotypes.Volume, e 164 | } 165 | createResponse, err := c.client.CreateVolume(params, c.storagePool.Name) 166 | if err != nil { 167 | - klog.Error(log("failed to create volume %s: %v", name, err)) 168 | - return nil, err 169 | + // don't log error details from client calls in events 170 | + klog.V(4).Infof(log("failed to create volume %s: %v", name, err)) 171 | + return nil, errors.New("failed to create volume: see kubernetes logs for details") 172 | } 173 | return c.Volume(sioVolumeID(createResponse.ID)) 174 | } 175 | @@ -244,8 +246,9 @@ func (c *sioClient) AttachVolume(id sioVolumeID, multipleMappings bool) error { 176 | volClient.Volume = &siotypes.Volume{ID: string(id)} 177 | 178 | if err := volClient.MapVolumeSdc(params); err != nil { 179 | - klog.Error(log("failed to attach volume id %s: %v", id, err)) 180 | - return err 181 | + // don't log error details from client calls in events 182 | + klog.V(4).Infof(log("failed to attach volume id %s: %v", id, err)) 183 | + return errors.New("failed to attach volume: see kubernetes logs for details") 184 | } 185 | 186 | klog.V(4).Info(log("volume %s attached successfully", id)) 187 | @@ -270,7 +273,9 @@ func (c *sioClient) DetachVolume(id sioVolumeID) error { 188 | volClient := sio.NewVolume(c.client) 189 | volClient.Volume = &siotypes.Volume{ID: string(id)} 190 | if err := volClient.UnmapVolumeSdc(params); err != nil { 191 | - return err 192 | + // don't log error details from client calls in events 193 | + klog.V(4).Infof(log("failed to detach volume id %s: %v", id, err)) 194 | + return errors.New("failed to detach volume: see kubernetes logs for details") 195 | } 196 | return nil 197 | } 198 | @@ -288,7 +293,9 @@ func (c *sioClient) DeleteVolume(id sioVolumeID) error { 199 | volClient := sio.NewVolume(c.client) 200 | volClient.Volume = vol 201 | if err := volClient.RemoveVolume("ONLY_ME"); err != nil { 202 | - return err 203 | + // don't log error details from client calls in events 204 | + klog.V(4).Infof(log("failed to remove volume id %s: %v", id, err)) 205 | + return errors.New("failed to remove volume: see kubernetes logs for details") 206 | } 207 | return nil 208 | } 209 | @@ -307,8 +314,9 @@ func (c *sioClient) IID() (string, error) { 210 | } 211 | sdc, err := c.sysClient.FindSdc("SdcGUID", guid) 212 | if err != nil { 213 | - klog.Error(log("failed to retrieve sdc info %s", err)) 214 | - return "", err 215 | + // don't log error details from client calls in events 216 | + klog.V(4).Infof(log("failed to retrieve sdc info %s", err)) 217 | + return "", errors.New("failed to retrieve sdc info: see kubernetes logs for details") 218 | } 219 | c.instanceID = sdc.Sdc.ID 220 | klog.V(4).Info(log("retrieved instanceID %s", c.instanceID)) 221 | @@ -473,12 +481,15 @@ func (c *sioClient) WaitForDetachedDevice(token string) error { 222 | // *********************************************************************** 223 | func (c *sioClient) findSystem(sysname string) (sys *siotypes.System, err error) { 224 | if c.sysClient, err = c.client.FindSystem("", sysname, ""); err != nil { 225 | - return nil, err 226 | + // don't log error details from clients in events 227 | + klog.V(4).Infof(log("failed to find system %q: %v", sysname, err)) 228 | + return nil, errors.New("failed to find system: see kubernetes logs for details") 229 | } 230 | systems, err := c.client.GetInstance("") 231 | if err != nil { 232 | - klog.Error(log("failed to retrieve instances: %v", err)) 233 | - return nil, err 234 | + // don't log error details from clients in events 235 | + klog.V(4).Infof(log("failed to retrieve instances: %v", err)) 236 | + return nil, errors.New("failed to retrieve instances: see kubernetes logs for details") 237 | } 238 | for _, sys = range systems { 239 | if sys.Name == sysname { 240 | @@ -494,8 +505,9 @@ func (c *sioClient) findProtectionDomain(pdname string) (*siotypes.ProtectionDom 241 | if c.sysClient != nil { 242 | protectionDomain, err := c.sysClient.FindProtectionDomain("", pdname, "") 243 | if err != nil { 244 | - klog.Error(log("failed to retrieve protection domains: %v", err)) 245 | - return nil, err 246 | + // don't log error details from clients in events 247 | + klog.V(4).Infof(log("failed to retrieve protection domains: %v", err)) 248 | + return nil, errors.New("failed to retrieve protection domains: see kubernetes logs for details") 249 | } 250 | c.pdClient.ProtectionDomain = protectionDomain 251 | return protectionDomain, nil 252 | @@ -509,8 +521,9 @@ func (c *sioClient) findStoragePool(spname string) (*siotypes.StoragePool, error 253 | if c.pdClient != nil { 254 | sp, err := c.pdClient.FindStoragePool("", spname, "") 255 | if err != nil { 256 | - klog.Error(log("failed to retrieve storage pool: %v", err)) 257 | - return nil, err 258 | + // don't log error details from clients in events 259 | + klog.V(4).Infof(log("failed to retrieve storage pool: %v", err)) 260 | + return nil, errors.New("failed to retrieve storage pool: see kubernetes logs for details") 261 | } 262 | c.spClient.StoragePool = sp 263 | return sp, nil 264 | @@ -520,14 +533,32 @@ func (c *sioClient) findStoragePool(spname string) (*siotypes.StoragePool, error 265 | } 266 | 267 | func (c *sioClient) getVolumes() ([]*siotypes.Volume, error) { 268 | - return c.client.GetVolume("", "", "", "", true) 269 | + volumes, err := c.client.GetVolume("", "", "", "", true) 270 | + if err != nil { 271 | + // don't log error details from clients in events 272 | + klog.V(4).Infof(log("failed to get volumes: %v", err)) 273 | + return nil, errors.New("failed to get volumes: see kubernetes logs for details") 274 | + } 275 | + return volumes, nil 276 | } 277 | func (c *sioClient) getVolumesByID(id sioVolumeID) ([]*siotypes.Volume, error) { 278 | - return c.client.GetVolume("", string(id), "", "", true) 279 | + volumes, err := c.client.GetVolume("", string(id), "", "", true) 280 | + if err != nil { 281 | + // don't log error details from clients in events 282 | + klog.V(4).Infof(log("failed to get volumes by id: %v", err)) 283 | + return nil, errors.New("failed to get volumes by id: see kubernetes logs for details") 284 | + } 285 | + return volumes, nil 286 | } 287 | 288 | func (c *sioClient) getVolumesByName(name string) ([]*siotypes.Volume, error) { 289 | - return c.client.GetVolume("", "", "", name, true) 290 | + volumes, err := c.client.GetVolume("", "", "", name, true) 291 | + if err != nil { 292 | + // don't log error details from clients in events 293 | + klog.V(4).Infof(log("failed to get volumes by name: %v", err)) 294 | + return nil, errors.New("failed to get volumes by name: see kubernetes logs for details") 295 | + } 296 | + return volumes, nil 297 | } 298 | 299 | func (c *sioClient) getSdcPath() string { 300 | diff --git a/pkg/volume/storageos/storageos_util.go b/pkg/volume/storageos/storageos_util.go 301 | index eb669186f61..ae06b1ebcc1 100644 302 | --- a/pkg/volume/storageos/storageos_util.go 303 | +++ b/pkg/volume/storageos/storageos_util.go 304 | @@ -122,8 +122,9 @@ func (u *storageosUtil) CreateVolume(p *storageosProvisioner) (*storageosVolume, 305 | 306 | vol, err := u.api.VolumeCreate(opts) 307 | if err != nil { 308 | - klog.Errorf("volume create failed for volume %q (%v)", opts.Name, err) 309 | - return nil, err 310 | + // don't log error details from client calls in events 311 | + klog.V(4).Infof("volume create failed for volume %q (%v)", opts.Name, err) 312 | + return nil, errors.New("volume create failed: see kube-controller-manager.log for details") 313 | } 314 | return &storageosVolume{ 315 | ID: vol.ID, 316 | @@ -286,7 +287,12 @@ func (u *storageosUtil) DeleteVolume(d *storageosDeleter) error { 317 | Namespace: d.volNamespace, 318 | Force: true, 319 | } 320 | - return u.api.VolumeDelete(opts) 321 | + if err := u.api.VolumeDelete(opts); err != nil { 322 | + // don't log error details from client calls in events 323 | + klog.V(4).Infof("volume deleted failed for volume %q in namespace %q: %v", d.volName, d.volNamespace, err) 324 | + return errors.New("volume delete failed: see kube-controller-manager.log for details") 325 | + } 326 | + return nil 327 | } 328 | 329 | // Get the node's device path from the API, falling back to the default if not 330 | -------------------------------------------------------------------------------- /patches/CVE-2020-8558.1.12.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Casey Callendrello 3 | Date: Fri, 29 May 2020 13:03:37 +0200 4 | Subject: [PATCH] kubelet: block non-forwarded packets from crossing the 5 | localhost boundary 6 | 7 | We set route_localnet so that host-network processes can connect to 8 | <127.0.0.1:NodePort> and it still works. This, however, is too 9 | permissive. 10 | 11 | So, block martians that are not already in conntrack. 12 | 13 | See: #90259 14 | Signed-off-by: Casey Callendrello 15 | --- 16 | pkg/kubelet/kubelet_network_linux.go | 16 ++++++++++++++++ 17 | 1 file changed, 16 insertions(+) 18 | 19 | diff --git a/pkg/kubelet/kubelet_network_linux.go b/pkg/kubelet/kubelet_network_linux.go 20 | index 002b226b190..f1330b875ca 100644 21 | --- a/pkg/kubelet/kubelet_network_linux.go 22 | +++ b/pkg/kubelet/kubelet_network_linux.go 23 | @@ -68,6 +68,22 @@ func (kl *Kubelet) syncNetworkUtil() { 24 | glog.Errorf("Failed to ensure rule to drop packet marked by %v in %v chain %v: %v", KubeMarkDropChain, utiliptables.TableFilter, KubeFirewallChain, err) 25 | return 26 | } 27 | + 28 | + // drop all non-local packets to localhost if they're not part of an existing 29 | + // forwarded connection. See #90259 30 | + if !kl.iptClient.IsIpv6() { // ipv6 doesn't have this issue 31 | + if _, err := kl.iptClient.EnsureRule(utiliptables.Append, utiliptables.TableFilter, KubeFirewallChain, 32 | + "-m", "comment", "--comment", "block incoming localnet connections", 33 | + "--dst", "127.0.0.0/8", 34 | + "!", "--src", "127.0.0.0/8", 35 | + "-m", "conntrack", 36 | + "!", "--ctstate", "RELATED,ESTABLISHED,DNAT", 37 | + "-j", "DROP"); err != nil { 38 | + glog.Errorf("Failed to ensure rule to drop invalid localhost packets in %v chain %v: %v", utiliptables.TableFilter, KubeFirewallChain, err) 39 | + return 40 | + } 41 | + } 42 | + 43 | if _, err := kl.iptClient.EnsureRule(utiliptables.Prepend, utiliptables.TableFilter, utiliptables.ChainOutput, "-j", string(KubeFirewallChain)); err != nil { 44 | glog.Errorf("Failed to ensure that %s chain %s jumps to %s: %v", utiliptables.TableFilter, utiliptables.ChainOutput, KubeFirewallChain, err) 45 | return 46 | -------------------------------------------------------------------------------- /patches/CVE-2020-8559.1.12.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Tim Allclair 3 | Date: Wed, 17 Jun 2020 11:09:02 -0700 4 | Subject: [PATCH] Don't return proxied redirects to the client 5 | 6 | --- 7 | staging/src/k8s.io/apimachinery/pkg/util/net/http.go | 2 +- 8 | .../k8s.io/apimachinery/pkg/util/proxy/upgradeaware.go | 10 ++++++++++ 9 | 2 files changed, 11 insertions(+), 1 deletion(-) 10 | 11 | diff --git a/staging/src/k8s.io/apimachinery/pkg/util/net/http.go b/staging/src/k8s.io/apimachinery/pkg/util/net/http.go 12 | index 7c2a5e6286d..75750aaacc2 100644 13 | --- a/staging/src/k8s.io/apimachinery/pkg/util/net/http.go 14 | +++ b/staging/src/k8s.io/apimachinery/pkg/util/net/http.go 15 | @@ -404,7 +404,7 @@ redirectLoop: 16 | 17 | // Only follow redirects to the same host. Otherwise, propagate the redirect response back. 18 | if requireSameHostRedirects && location.Hostname() != originalLocation.Hostname() { 19 | - break redirectLoop 20 | + return nil, nil, fmt.Errorf("hostname mismatch: expected %s, found %s", originalLocation.Hostname(), location.Hostname()) 21 | } 22 | 23 | // Reset the connection. 24 | diff --git a/staging/src/k8s.io/apimachinery/pkg/util/proxy/upgradeaware.go b/staging/src/k8s.io/apimachinery/pkg/util/proxy/upgradeaware.go 25 | index 4c6c5751680..402bef86f3c 100644 26 | --- a/staging/src/k8s.io/apimachinery/pkg/util/proxy/upgradeaware.go 27 | +++ b/staging/src/k8s.io/apimachinery/pkg/util/proxy/upgradeaware.go 28 | @@ -284,6 +284,16 @@ func (h *UpgradeAwareHandler) tryUpgrade(w http.ResponseWriter, req *http.Reques 29 | rawResponse = headerBytes 30 | } 31 | 32 | + // If the backend did not upgrade the request, return an error to the client. If the response was 33 | + // an error, the error is forwarded directly after the connection is hijacked. Otherwise, just 34 | + // return a generic error here. 35 | + if backendHTTPResponse.StatusCode != http.StatusSwitchingProtocols && backendHTTPResponse.StatusCode < 400 { 36 | + err := fmt.Errorf("invalid upgrade response: status code %d", backendHTTPResponse.StatusCode) 37 | + glog.Errorf("Proxy upgrade error: %v", err) 38 | + h.Responder.Error(w, req, err) 39 | + return true 40 | + } 41 | + 42 | // Once the connection is hijacked, the ErrorResponder will no longer work, so 43 | // hijacking should be the last step in the upgrade. 44 | requestHijacker, ok := w.(http.Hijacker) 45 | -------------------------------------------------------------------------------- /patches/CVE-2020-8559.1.13.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Tim Allclair 3 | Date: Wed, 17 Jun 2020 11:09:02 -0700 4 | Subject: [PATCH] Don't return proxied redirects to the client 5 | 6 | --- 7 | staging/src/k8s.io/apimachinery/pkg/util/net/http.go | 2 +- 8 | .../k8s.io/apimachinery/pkg/util/proxy/upgradeaware.go | 10 ++++++++++ 9 | 2 files changed, 11 insertions(+), 1 deletion(-) 10 | 11 | diff --git a/staging/src/k8s.io/apimachinery/pkg/util/net/http.go b/staging/src/k8s.io/apimachinery/pkg/util/net/http.go 12 | index 155667cdfc7..adab4bc0213 100644 13 | --- a/staging/src/k8s.io/apimachinery/pkg/util/net/http.go 14 | +++ b/staging/src/k8s.io/apimachinery/pkg/util/net/http.go 15 | @@ -404,7 +404,7 @@ redirectLoop: 16 | 17 | // Only follow redirects to the same host. Otherwise, propagate the redirect response back. 18 | if requireSameHostRedirects && location.Hostname() != originalLocation.Hostname() { 19 | - break redirectLoop 20 | + return nil, nil, fmt.Errorf("hostname mismatch: expected %s, found %s", originalLocation.Hostname(), location.Hostname()) 21 | } 22 | 23 | // Reset the connection. 24 | diff --git a/staging/src/k8s.io/apimachinery/pkg/util/proxy/upgradeaware.go b/staging/src/k8s.io/apimachinery/pkg/util/proxy/upgradeaware.go 25 | index 3c8e09399f5..501deb9c00e 100644 26 | --- a/staging/src/k8s.io/apimachinery/pkg/util/proxy/upgradeaware.go 27 | +++ b/staging/src/k8s.io/apimachinery/pkg/util/proxy/upgradeaware.go 28 | @@ -284,6 +284,16 @@ func (h *UpgradeAwareHandler) tryUpgrade(w http.ResponseWriter, req *http.Reques 29 | rawResponse = headerBytes 30 | } 31 | 32 | + // If the backend did not upgrade the request, return an error to the client. If the response was 33 | + // an error, the error is forwarded directly after the connection is hijacked. Otherwise, just 34 | + // return a generic error here. 35 | + if backendHTTPResponse.StatusCode != http.StatusSwitchingProtocols && backendHTTPResponse.StatusCode < 400 { 36 | + err := fmt.Errorf("invalid upgrade response: status code %d", backendHTTPResponse.StatusCode) 37 | + klog.Errorf("Proxy upgrade error: %v", err) 38 | + h.Responder.Error(w, req, err) 39 | + return true 40 | + } 41 | + 42 | // Once the connection is hijacked, the ErrorResponder will no longer work, so 43 | // hijacking should be the last step in the upgrade. 44 | requestHijacker, ok := w.(http.Hijacker) 45 | -------------------------------------------------------------------------------- /patches/fix-etcd-health.1.11.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Jingyi Hu 3 | Date: Tue, 29 Oct 2019 13:10:29 -0700 4 | Subject: [PATCH] Update etcd.sh to use v3 endpoint 5 | 6 | --- 7 | hack/lib/etcd.sh | 4 ++-- 8 | 1 file changed, 2 insertions(+), 2 deletions(-) 9 | 10 | diff --git a/hack/lib/etcd.sh b/hack/lib/etcd.sh 11 | index cbe1083daaa..ac098a279a2 100755 12 | --- a/hack/lib/etcd.sh 13 | +++ b/hack/lib/etcd.sh 14 | @@ -78,8 +78,8 @@ kube::etcd::start() { 15 | ETCD_PID=$! 16 | 17 | echo "Waiting for etcd to come up." 18 | - kube::util::wait_for_url "http://${ETCD_HOST}:${ETCD_PORT}/v2/machines" "etcd: " 0.25 80 19 | - curl -fs -X PUT "http://${ETCD_HOST}:${ETCD_PORT}/v2/keys/_test" 20 | + kube::util::wait_for_url "http://${ETCD_HOST}:${ETCD_PORT}/health" "etcd: " 0.25 80 21 | + curl -fs -X POST "http://${ETCD_HOST}:${ETCD_PORT}/v3/kv/put" -d '{"key": "X3Rlc3Q=", "value": ""}' 22 | } 23 | 24 | kube::etcd::stop() { 25 | -------------------------------------------------------------------------------- /patches/fix-etcd-health.1.16.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Jingyi Hu 3 | Date: Tue, 29 Oct 2019 13:10:29 -0700 4 | Subject: [PATCH] Update etcd.sh to use v3 endpoint 5 | 6 | --- 7 | hack/lib/etcd.sh | 4 ++-- 8 | 1 file changed, 2 insertions(+), 2 deletions(-) 9 | 10 | diff --git a/hack/lib/etcd.sh b/hack/lib/etcd.sh 11 | index fe71c888775..6f7e4c5e18a 100755 12 | --- a/hack/lib/etcd.sh 13 | +++ b/hack/lib/etcd.sh 14 | @@ -80,8 +80,8 @@ kube::etcd::start() { 15 | ETCD_PID=$! 16 | 17 | echo "Waiting for etcd to come up." 18 | - kube::util::wait_for_url "${KUBE_INTEGRATION_ETCD_URL}/v2/machines" "etcd: " 0.25 80 19 | - curl -fs -X PUT "${KUBE_INTEGRATION_ETCD_URL}/v2/keys/_test" 20 | + kube::util::wait_for_url "${KUBE_INTEGRATION_ETCD_URL}/health" "etcd: " 0.25 80 21 | + curl -fs -X POST "${KUBE_INTEGRATION_ETCD_URL}/v3/kv/put" -d '{"key": "X3Rlc3Q=", "value": ""}' 22 | } 23 | 24 | kube::etcd::stop() { 25 | -------------------------------------------------------------------------------- /patches/fix-etcd-put-key.1.11.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Shiming Zhang 3 | Date: Wed, 28 Jul 2021 10:32:45 +0800 4 | Subject: [PATCH] Remove writable verification in etcd startup 5 | 6 | --- 7 | hack/lib/etcd.sh | 1 - 8 | 1 file changed, 1 deletion(-) 9 | 10 | diff --git a/hack/lib/etcd.sh b/hack/lib/etcd.sh 11 | index ac098a279a2..036d63ae374 100755 12 | --- a/hack/lib/etcd.sh 13 | +++ b/hack/lib/etcd.sh 14 | @@ -79,7 +79,6 @@ kube::etcd::start() { 15 | 16 | echo "Waiting for etcd to come up." 17 | kube::util::wait_for_url "http://${ETCD_HOST}:${ETCD_PORT}/health" "etcd: " 0.25 80 18 | - curl -fs -X POST "http://${ETCD_HOST}:${ETCD_PORT}/v3/kv/put" -d '{"key": "X3Rlc3Q=", "value": ""}' 19 | } 20 | 21 | kube::etcd::stop() { 22 | -------------------------------------------------------------------------------- /patches/fix-etcd-put-key.1.23.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Shiming Zhang 3 | Date: Wed, 28 Jul 2021 10:32:45 +0800 4 | Subject: [PATCH] Remove writable verification in etcd startup 5 | 6 | --- 7 | hack/lib/etcd.sh | 1 - 8 | 1 file changed, 1 deletion(-) 9 | 10 | diff --git a/hack/lib/etcd.sh b/hack/lib/etcd.sh 11 | index a548dc59c45..515187c2adc 100755 12 | --- a/hack/lib/etcd.sh 13 | +++ b/hack/lib/etcd.sh 14 | @@ -88,7 +88,6 @@ kube::etcd::start() { 15 | 16 | echo "Waiting for etcd to come up." 17 | kube::util::wait_for_url "${KUBE_INTEGRATION_ETCD_URL}/health" "etcd: " 0.25 80 18 | - curl -fs -X POST "${KUBE_INTEGRATION_ETCD_URL}/v3/kv/put" -d '{"key": "X3Rlc3Q=", "value": ""}' 19 | } 20 | 21 | kube::etcd::start_scraping() { 22 | -------------------------------------------------------------------------------- /patches/fix-etcd-put-key.1.24.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Shiming Zhang 3 | Date: Wed, 28 Jul 2021 10:32:45 +0800 4 | Subject: [PATCH] Remove writable verification in etcd startup 5 | 6 | --- 7 | hack/lib/etcd.sh | 1 - 8 | 1 file changed, 1 deletion(-) 9 | 10 | diff --git a/hack/lib/etcd.sh b/hack/lib/etcd.sh 11 | index 307d241d294..b01dd760bcc 100755 12 | --- a/hack/lib/etcd.sh 13 | +++ b/hack/lib/etcd.sh 14 | @@ -92,7 +92,6 @@ kube::etcd::start() { 15 | 16 | echo "Waiting for etcd to come up." 17 | kube::util::wait_for_url "${KUBE_INTEGRATION_ETCD_URL}/health" "etcd: " 0.25 80 18 | - curl -fs -X POST "${KUBE_INTEGRATION_ETCD_URL}/v3/kv/put" -d '{"key": "X3Rlc3Q=", "value": ""}' 19 | } 20 | 21 | kube::etcd::start_scraping() { 22 | -------------------------------------------------------------------------------- /patches/fix-image-name.1.12.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: =?UTF-8?q?Javier=20P=C3=A9rez=20Hern=C3=A1ndez?= 3 | Date: Thu, 11 Jul 2019 10:58:32 -0700 4 | Subject: [PATCH] release lib: docker save remove special name for amd64 5 | 6 | --- 7 | build/lib/release.sh | 16 ++-------------- 8 | 1 file changed, 2 insertions(+), 14 deletions(-) 9 | 10 | diff --git a/build/lib/release.sh b/build/lib/release.sh 11 | index ef7a5838e73..5f1ea62fd94 100644 12 | --- a/build/lib/release.sh 13 | +++ b/build/lib/release.sh 14 | @@ -335,20 +335,8 @@ function kube::release::create_docker_images_for_server() { 15 | local docker_build_path="${binary_dir}/${binary_name}.dockerbuild" 16 | local docker_file_path="${docker_build_path}/Dockerfile" 17 | local binary_file_path="${binary_dir}/${binary_name}" 18 | - local docker_image_tag="${docker_registry}" 19 | - local deprecated_image_tag="${deprecated_registry}" 20 | - if [[ ${arch} == "amd64" ]]; then 21 | - # If we are building a amd64 docker image, preserve the original 22 | - # image name 23 | - docker_image_tag+="/${binary_name}:${docker_tag}" 24 | - deprecated_image_tag+="/${binary_name}:${docker_tag}" 25 | - else 26 | - # If we are building a docker image for another architecture, 27 | - # append the arch in the image tag 28 | - docker_image_tag+="/${binary_name}-${arch}:${docker_tag}" 29 | - deprecated_image_tag+="/${binary_name}-${arch}:${docker_tag}" 30 | - fi 31 | - 32 | + local docker_image_tag="${docker_registry}/${binary_name}-${arch}:${docker_tag}" 33 | + local deprecated_image_tag="${deprecated_registry}/${binary_name}-${arch}:${docker_tag}" 34 | 35 | kube::log::status "Starting docker build for image: ${binary_name}-${arch}" 36 | ( 37 | -------------------------------------------------------------------------------- /patches/fix-kubectl-convert-97644.1.20.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Masashi Honma 3 | Date: Thu, 18 Feb 2021 08:24:07 +0900 4 | Subject: [PATCH] Fix tests using kubectl convert 5 | 6 | hack/make-rules/test-cmd.sh script fails with tariling errors. 7 | 8 | Error: unknown command "convert" for "kubectl" 9 | 10 | 1. This PR fixes the errors by replacing or removing the use of 11 | "kubectl convert" option because it was already removed. 12 | 13 | 2. Fix trailing shell check failure as well. 14 | In ./test/cmd/generic-resources.sh line 366: 15 | kube::test::get_object_assert deployment "{{range.items}}{{$image_field0}}:{{end}}" "${IMAGE_NGINX}:${IMAGE_NGINX}:" 16 | --- 17 | test/cmd/create.sh | 2 +- 18 | test/cmd/generic-resources.sh | 30 ++---------------------------- 19 | test/cmd/template-output.sh | 4 ---- 20 | 3 files changed, 3 insertions(+), 33 deletions(-) 21 | 22 | diff --git a/test/cmd/create.sh b/test/cmd/create.sh 23 | index 20f0e8add96..67bcf8ff59d 100755 24 | --- a/test/cmd/create.sh 25 | +++ b/test/cmd/create.sh 26 | @@ -85,7 +85,7 @@ run_kubectl_create_error_tests() { 27 | rm "${ERROR_FILE}" 28 | 29 | # Posting a pod to namespaces should fail. Also tests --raw forcing the post location 30 | - grep -q "cannot be handled as a Namespace: converting (v1.Pod)" <<< "$( kubectl convert -f test/fixtures/doc-yaml/admin/limitrange/valid-pod.yaml -o json | kubectl create "${kube_flags[@]}" --raw /api/v1/namespaces -f - --v=8 2>&1 )" 31 | + grep -q 'the object provided is unrecognized (must be of type Namespace)' <<< "$( kubectl create "${kube_flags[@]}" --raw /api/v1/namespaces -f test/fixtures/doc-yaml/admin/limitrange/valid-pod.yaml --v=8 2>&1 )" 32 | 33 | grep -q "raw and --edit are mutually exclusive" <<< "$( kubectl create "${kube_flags[@]}" --raw /api/v1/namespaces -f test/fixtures/doc-yaml/admin/limitrange/valid-pod.yaml --edit 2>&1 )" 34 | 35 | diff --git a/test/cmd/generic-resources.sh b/test/cmd/generic-resources.sh 36 | index 17f111580b2..b983118d463 100755 37 | --- a/test/cmd/generic-resources.sh 38 | +++ b/test/cmd/generic-resources.sh 39 | @@ -259,32 +259,6 @@ run_recursive_resources_tests() { 40 | kube::test::get_object_assert pods "{{range.items}}{{${labels_field}.status}}:{{end}}" 'replaced:replaced:' 41 | kube::test::if_has_string "${output_message}" 'error validating data: kind not set' 42 | 43 | - 44 | - ### Convert deployment YAML file locally without affecting the live deployment. 45 | - # Pre-condition: no deployments exist 46 | - kube::test::get_object_assert deployment "{{range.items}}{{$id_field}}:{{end}}" '' 47 | - # Command 48 | - # Create a deployment (revision 1) 49 | - kubectl create -f hack/testdata/deployment-revision1.yaml "${kube_flags[@]}" 50 | - kube::test::get_object_assert deployment "{{range.items}}{{$id_field}}:{{end}}" 'nginx:' 51 | - kube::test::get_object_assert deployment "{{range.items}}{{${image_field0:?}}}:{{end}}" "${IMAGE_DEPLOYMENT_R1}:" 52 | - # Command 53 | - output_message=$(kubectl convert --local -f hack/testdata/deployment-revision1.yaml --output-version=extensions/v1beta1 -o yaml "${kube_flags[@]}") 54 | - # Post-condition: apiVersion is still apps/v1 in the live deployment, but command output is the new value 55 | - kube::test::get_object_assert 'deployment nginx' "{{ .apiVersion }}" 'apps/v1' 56 | - kube::test::if_has_string "${output_message}" "extensions/v1beta1" 57 | - # Clean up 58 | - kubectl delete deployment nginx "${kube_flags[@]}" 59 | - 60 | - ## Convert multiple busybox PODs recursively from directory of YAML files 61 | - # Pre-condition: only busybox0 & busybox1 PODs exist 62 | - kube::test::wait_object_assert pods "{{range.items}}{{$id_field}}:{{end}}" 'busybox0:busybox1:' 63 | - # Command 64 | - output_message=$(! kubectl convert -f hack/testdata/recursive/pod --recursive 2>&1 "${kube_flags[@]}") 65 | - # Post-condition: busybox0 & busybox1 PODs are converted, and since busybox2 is malformed, it should error 66 | - kube::test::get_object_assert pods "{{range.items}}{{$id_field}}:{{end}}" 'busybox0:busybox1:' 67 | - kube::test::if_has_string "${output_message}" "Object 'Kind' is missing" 68 | - 69 | ## Get multiple busybox PODs recursively from directory of YAML files 70 | # Pre-condition: busybox0 & busybox1 PODs exist 71 | kube::test::get_object_assert pods "{{range.items}}{{$id_field}}:{{end}}" 'busybox0:busybox1:' 72 | @@ -389,11 +363,11 @@ run_recursive_resources_tests() { 73 | # Create deployments (revision 1) recursively from directory of YAML files 74 | ! kubectl create -f hack/testdata/recursive/deployment --recursive "${kube_flags[@]}" || exit 1 75 | kube::test::get_object_assert deployment "{{range.items}}{{$id_field}}:{{end}}" 'nginx0-deployment:nginx1-deployment:' 76 | - kube::test::get_object_assert deployment "{{range.items}}{{$image_field0}}:{{end}}" "${IMAGE_NGINX}:${IMAGE_NGINX}:" 77 | + kube::test::get_object_assert deployment "{{range.items}}{{${image_field0:?}}}:{{end}}" "${IMAGE_NGINX}:${IMAGE_NGINX}:" 78 | ## Rollback the deployments to revision 1 recursively 79 | output_message=$(! kubectl rollout undo -f hack/testdata/recursive/deployment --recursive --to-revision=1 2>&1 "${kube_flags[@]}") 80 | # Post-condition: nginx0 & nginx1 should be a no-op, and since nginx2 is malformed, it should error 81 | - kube::test::get_object_assert deployment "{{range.items}}{{$image_field0}}:{{end}}" "${IMAGE_NGINX}:${IMAGE_NGINX}:" 82 | + kube::test::get_object_assert deployment "{{range.items}}{{${image_field0:?}}}:{{end}}" "${IMAGE_NGINX}:${IMAGE_NGINX}:" 83 | kube::test::if_has_string "${output_message}" "Object 'Kind' is missing" 84 | ## Pause the deployments recursively 85 | # shellcheck disable=SC2034 # PRESERVE_ERR_FILE is used in kubectl-with-retry 86 | diff --git a/test/cmd/template-output.sh b/test/cmd/template-output.sh 87 | index b5e9fff2e27..3155077b947 100755 88 | --- a/test/cmd/template-output.sh 89 | +++ b/test/cmd/template-output.sh 90 | @@ -62,10 +62,6 @@ run_template_output_tests() { 91 | output_message=$(kubectl "${kube_flags[@]:?}" expose -f hack/testdata/redis-slave-replicaset.yaml --save-config --port=80 --target-port=8000 --dry-run=client --template="{{ .metadata.name }}:") 92 | kube::test::if_has_string "${output_message}" 'redis-slave:' 93 | 94 | - # check that convert command supports --template output 95 | - output_message=$(kubectl convert "${kube_flags[@]:?}" -f hack/testdata/deployment-revision1.yaml --output-version=apps/v1beta1 --template="{{ .metadata.name }}:") 96 | - kube::test::if_has_string "${output_message}" 'nginx:' 97 | - 98 | # check that run command supports --template output 99 | output_message=$(kubectl "${kube_flags[@]:?}" run --dry-run=client --template="{{ .metadata.name }}:" pi --image=perl --restart=OnFailure -- perl -Mbignum=bpi -wle 'print bpi(2000)') 100 | kube::test::if_has_string "${output_message}" 'pi:' 101 | -------------------------------------------------------------------------------- /patches/fix-missing-env-91500.1.18.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: David Eads 3 | Date: Wed, 27 May 2020 11:44:14 -0400 4 | Subject: [PATCH] reduce race risk in kubelet for missing 5 | KUBERNETES_SERVICE_HOST 6 | 7 | --- 8 | pkg/kubelet/kubelet.go | 19 +++- 9 | pkg/kubelet/kubelet_pods.go | 12 +++ 10 | pkg/kubelet/kubelet_pods_test.go | 153 +++++++++++++++++++------------ 11 | pkg/kubelet/kubelet_test.go | 1 + 12 | 4 files changed, 122 insertions(+), 63 deletions(-) 13 | 14 | diff --git a/pkg/kubelet/kubelet.go b/pkg/kubelet/kubelet.go 15 | index 1d571c33b07..919629b3709 100644 16 | --- a/pkg/kubelet/kubelet.go 17 | +++ b/pkg/kubelet/kubelet.go 18 | @@ -530,13 +530,18 @@ func NewMainKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration, 19 | PodCgroupRoot: kubeDeps.ContainerManager.GetPodCgroupRoot(), 20 | } 21 | 22 | - serviceIndexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}) 23 | + var serviceLister corelisters.ServiceLister 24 | + var serviceHasSynced cache.InformerSynced 25 | if kubeDeps.KubeClient != nil { 26 | - serviceLW := cache.NewListWatchFromClient(kubeDeps.KubeClient.CoreV1().RESTClient(), "services", metav1.NamespaceAll, fields.Everything()) 27 | - r := cache.NewReflector(serviceLW, &v1.Service{}, serviceIndexer, 0) 28 | - go r.Run(wait.NeverStop) 29 | + kubeInformers := informers.NewSharedInformerFactory(kubeDeps.KubeClient, 0) 30 | + serviceLister = kubeInformers.Core().V1().Services().Lister() 31 | + serviceHasSynced = kubeInformers.Core().V1().Services().Informer().HasSynced 32 | + kubeInformers.Start(wait.NeverStop) 33 | + } else { 34 | + serviceIndexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}) 35 | + serviceLister = corelisters.NewServiceLister(serviceIndexer) 36 | + serviceHasSynced = func() bool { return true } 37 | } 38 | - serviceLister := corelisters.NewServiceLister(serviceIndexer) 39 | 40 | // TODO: get the real node object of ourself, 41 | // and use the real node name and UID. 42 | @@ -587,6 +592,7 @@ func NewMainKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration, 43 | registerSchedulable: registerSchedulable, 44 | dnsConfigurer: dns.NewConfigurer(kubeDeps.Recorder, nodeRef, parsedNodeIP, clusterDNS, kubeCfg.ClusterDomain, kubeCfg.ResolverConfig), 45 | serviceLister: serviceLister, 46 | + serviceHasSynced: serviceHasSynced, 47 | nodeLister: nodeLister, 48 | nodeHasSynced: nodeHasSynced, 49 | masterServiceNamespace: masterServiceNamespace, 50 | @@ -976,6 +982,9 @@ type Kubelet struct { 51 | masterServiceNamespace string 52 | // serviceLister knows how to list services 53 | serviceLister serviceLister 54 | + // serviceHasSynced indicates whether services have been sync'd at least once. 55 | + // Check this before trusting a response from the lister. 56 | + serviceHasSynced cache.InformerSynced 57 | // nodeLister knows how to list nodes 58 | nodeLister corelisters.NodeLister 59 | // nodeHasSynced indicates whether nodes have been sync'd at least once. 60 | diff --git a/pkg/kubelet/kubelet_pods.go b/pkg/kubelet/kubelet_pods.go 61 | index 65a9fd74627..4feff10400d 100644 62 | --- a/pkg/kubelet/kubelet_pods.go 63 | +++ b/pkg/kubelet/kubelet_pods.go 64 | @@ -567,6 +567,18 @@ func (kl *Kubelet) makeEnvironmentVariables(pod *v1.Pod, container *v1.Container 65 | return nil, fmt.Errorf("nil pod.spec.enableServiceLinks encountered, cannot construct envvars") 66 | } 67 | 68 | + // If the pod originates from the kube-api, when we know that the kube-apiserver is responding and the kubelet's credentials are valid. 69 | + // Knowing this, it is reasonable to wait until the service lister has synchronized at least once before attempting to build 70 | + // a service env var map. This doesn't present the race below from happening entirely, but it does prevent the "obvious" 71 | + // failure case of services simply not having completed a list operation that can reasonably be expected to succeed. 72 | + // One common case this prevents is a kubelet restart reading pods before services and some pod not having the 73 | + // KUBERNETES_SERVICE_HOST injected because we didn't wait a short time for services to sync before proceeding. 74 | + // The KUBERNETES_SERVICE_HOST link is special because it is unconditionally injected into pods and is read by the 75 | + // in-cluster-config for pod clients 76 | + if !kubetypes.IsStaticPod(pod) && !kl.serviceHasSynced() { 77 | + return nil, fmt.Errorf("services have not yet been read at least once, cannot construct envvars") 78 | + } 79 | + 80 | var result []kubecontainer.EnvVar 81 | // Note: These are added to the docker Config, but are not included in the checksum computed 82 | // by kubecontainer.HashContainer(...). That way, we can still determine whether an 83 | diff --git a/pkg/kubelet/kubelet_pods_test.go b/pkg/kubelet/kubelet_pods_test.go 84 | index a542845c46e..190a9f6af41 100644 85 | --- a/pkg/kubelet/kubelet_pods_test.go 86 | +++ b/pkg/kubelet/kubelet_pods_test.go 87 | @@ -48,6 +48,7 @@ import ( 88 | containertest "k8s.io/kubernetes/pkg/kubelet/container/testing" 89 | "k8s.io/kubernetes/pkg/kubelet/server/portforward" 90 | "k8s.io/kubernetes/pkg/kubelet/server/remotecommand" 91 | + kubetypes "k8s.io/kubernetes/pkg/kubelet/types" 92 | "k8s.io/kubernetes/pkg/volume/util/hostutil" 93 | "k8s.io/kubernetes/pkg/volume/util/subpath" 94 | ) 95 | @@ -454,12 +455,36 @@ func TestMakeEnvironmentVariables(t *testing.T) { 96 | container *v1.Container // the container to use 97 | masterServiceNs string // the namespace to read master service info from 98 | nilLister bool // whether the lister should be nil 99 | + staticPod bool // whether the pod should be a static pod (versus an API pod) 100 | + unsyncedServices bool // whether the services should NOT be synced 101 | configMap *v1.ConfigMap // an optional ConfigMap to pull from 102 | secret *v1.Secret // an optional Secret to pull from 103 | expectedEnvs []kubecontainer.EnvVar // a set of expected environment vars 104 | expectedError bool // does the test fail 105 | expectedEvent string // does the test emit an event 106 | }{ 107 | + { 108 | + name: "if services aren't synced, non-static pods should fail", 109 | + ns: "test1", 110 | + enableServiceLinks: &falseValue, 111 | + container: &v1.Container{Env: []v1.EnvVar{}}, 112 | + masterServiceNs: metav1.NamespaceDefault, 113 | + nilLister: false, 114 | + staticPod: false, 115 | + unsyncedServices: true, 116 | + expectedEnvs: []kubecontainer.EnvVar{}, 117 | + expectedError: true, 118 | + }, 119 | + { 120 | + name: "if services aren't synced, static pods should succeed", // if there is no service 121 | + ns: "test1", 122 | + enableServiceLinks: &falseValue, 123 | + container: &v1.Container{Env: []v1.EnvVar{}}, 124 | + masterServiceNs: metav1.NamespaceDefault, 125 | + nilLister: false, 126 | + staticPod: true, 127 | + unsyncedServices: true, 128 | + }, 129 | { 130 | name: "api server = Y, kubelet = Y", 131 | ns: "test1", 132 | @@ -1606,71 +1631,83 @@ func TestMakeEnvironmentVariables(t *testing.T) { 133 | } 134 | 135 | for _, tc := range testCases { 136 | - fakeRecorder := record.NewFakeRecorder(1) 137 | - testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */) 138 | - testKubelet.kubelet.recorder = fakeRecorder 139 | - defer testKubelet.Cleanup() 140 | - kl := testKubelet.kubelet 141 | - kl.masterServiceNamespace = tc.masterServiceNs 142 | - if tc.nilLister { 143 | - kl.serviceLister = nil 144 | - } else { 145 | - kl.serviceLister = testServiceLister{services} 146 | - } 147 | + t.Run(tc.name, func(t *testing.T) { 148 | + fakeRecorder := record.NewFakeRecorder(1) 149 | + testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */) 150 | + testKubelet.kubelet.recorder = fakeRecorder 151 | + defer testKubelet.Cleanup() 152 | + kl := testKubelet.kubelet 153 | + kl.masterServiceNamespace = tc.masterServiceNs 154 | + if tc.nilLister { 155 | + kl.serviceLister = nil 156 | + } else if tc.unsyncedServices { 157 | + kl.serviceLister = testServiceLister{} 158 | + kl.serviceHasSynced = func() bool { return false } 159 | + } else { 160 | + kl.serviceLister = testServiceLister{services} 161 | + kl.serviceHasSynced = func() bool { return true } 162 | + } 163 | + 164 | + testKubelet.fakeKubeClient.AddReactor("get", "configmaps", func(action core.Action) (bool, runtime.Object, error) { 165 | + var err error 166 | + if tc.configMap == nil { 167 | + err = apierrors.NewNotFound(action.GetResource().GroupResource(), "configmap-name") 168 | + } 169 | + return true, tc.configMap, err 170 | + }) 171 | + testKubelet.fakeKubeClient.AddReactor("get", "secrets", func(action core.Action) (bool, runtime.Object, error) { 172 | + var err error 173 | + if tc.secret == nil { 174 | + err = apierrors.NewNotFound(action.GetResource().GroupResource(), "secret-name") 175 | + } 176 | + return true, tc.secret, err 177 | + }) 178 | + 179 | + testKubelet.fakeKubeClient.AddReactor("get", "secrets", func(action core.Action) (bool, runtime.Object, error) { 180 | + var err error 181 | + if tc.secret == nil { 182 | + err = errors.New("no secret defined") 183 | + } 184 | + return true, tc.secret, err 185 | + }) 186 | 187 | - testKubelet.fakeKubeClient.AddReactor("get", "configmaps", func(action core.Action) (bool, runtime.Object, error) { 188 | - var err error 189 | - if tc.configMap == nil { 190 | - err = apierrors.NewNotFound(action.GetResource().GroupResource(), "configmap-name") 191 | + testPod := &v1.Pod{ 192 | + ObjectMeta: metav1.ObjectMeta{ 193 | + Namespace: tc.ns, 194 | + Name: "dapi-test-pod-name", 195 | + Annotations: map[string]string{}, 196 | + }, 197 | + Spec: v1.PodSpec{ 198 | + ServiceAccountName: "special", 199 | + NodeName: "node-name", 200 | + EnableServiceLinks: tc.enableServiceLinks, 201 | + }, 202 | } 203 | - return true, tc.configMap, err 204 | - }) 205 | - testKubelet.fakeKubeClient.AddReactor("get", "secrets", func(action core.Action) (bool, runtime.Object, error) { 206 | - var err error 207 | - if tc.secret == nil { 208 | - err = apierrors.NewNotFound(action.GetResource().GroupResource(), "secret-name") 209 | + podIP := "1.2.3.4" 210 | + podIPs := []string{"1.2.3.4,fd00::6"} 211 | + if tc.staticPod { 212 | + testPod.Annotations[kubetypes.ConfigSourceAnnotationKey] = "file" 213 | } 214 | - return true, tc.secret, err 215 | - }) 216 | 217 | - testKubelet.fakeKubeClient.AddReactor("get", "secrets", func(action core.Action) (bool, runtime.Object, error) { 218 | - var err error 219 | - if tc.secret == nil { 220 | - err = errors.New("no secret defined") 221 | + t.Logf("makeEnvironmentVariables testPod %v; container: %v; pod IP: %v; pod IPs: %v.", testPod, tc.container, podIP, podIPs) 222 | + result, err := kl.makeEnvironmentVariables(testPod, tc.container, podIP, podIPs) 223 | + select { 224 | + case e := <-fakeRecorder.Events: 225 | + assert.Equal(t, tc.expectedEvent, e) 226 | + default: 227 | + assert.Equal(t, "", tc.expectedEvent) 228 | + } 229 | + if tc.expectedError { 230 | + assert.Error(t, err, tc.name) 231 | + } else { 232 | + assert.NoError(t, err, "[%s]", tc.name) 233 | + 234 | + sort.Sort(envs(result)) 235 | + sort.Sort(envs(tc.expectedEnvs)) 236 | + assert.Equal(t, tc.expectedEnvs, result, "[%s] env entries", tc.name) 237 | } 238 | - return true, tc.secret, err 239 | }) 240 | 241 | - testPod := &v1.Pod{ 242 | - ObjectMeta: metav1.ObjectMeta{ 243 | - Namespace: tc.ns, 244 | - Name: "dapi-test-pod-name", 245 | - }, 246 | - Spec: v1.PodSpec{ 247 | - ServiceAccountName: "special", 248 | - NodeName: "node-name", 249 | - EnableServiceLinks: tc.enableServiceLinks, 250 | - }, 251 | - } 252 | - podIP := "1.2.3.4" 253 | - podIPs := []string{"1.2.3.4,fd00::6"} 254 | - 255 | - result, err := kl.makeEnvironmentVariables(testPod, tc.container, podIP, podIPs) 256 | - select { 257 | - case e := <-fakeRecorder.Events: 258 | - assert.Equal(t, tc.expectedEvent, e) 259 | - default: 260 | - assert.Equal(t, "", tc.expectedEvent) 261 | - } 262 | - if tc.expectedError { 263 | - assert.Error(t, err, tc.name) 264 | - } else { 265 | - assert.NoError(t, err, "[%s]", tc.name) 266 | - 267 | - sort.Sort(envs(result)) 268 | - sort.Sort(envs(tc.expectedEnvs)) 269 | - assert.Equal(t, tc.expectedEnvs, result, "[%s] env entries", tc.name) 270 | - } 271 | } 272 | } 273 | 274 | diff --git a/pkg/kubelet/kubelet_test.go b/pkg/kubelet/kubelet_test.go 275 | index 748a92463ce..9da1566fe89 100644 276 | --- a/pkg/kubelet/kubelet_test.go 277 | +++ b/pkg/kubelet/kubelet_test.go 278 | @@ -180,6 +180,7 @@ func newTestKubeletWithImageList( 279 | kubelet.sourcesReady = config.NewSourcesReady(func(_ sets.String) bool { return true }) 280 | kubelet.masterServiceNamespace = metav1.NamespaceDefault 281 | kubelet.serviceLister = testServiceLister{} 282 | + kubelet.serviceHasSynced = func() bool { return true } 283 | kubelet.nodeHasSynced = func() bool { return true } 284 | kubelet.nodeLister = testNodeLister{ 285 | nodes: []*v1.Node{ 286 | -------------------------------------------------------------------------------- /patches/fix-run-docker.1.24.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Shiming Zhang 3 | Date: Tue, 27 Jul 2021 16:43:27 +0800 4 | Subject: [PATCH 1/2] Run docker as root in tests 5 | 6 | --- 7 | build/common.sh | 2 +- 8 | 1 file changed, 1 insertion(+), 1 deletion(-) 9 | 10 | diff --git a/build/common.sh b/build/common.sh 11 | index 257d36b2fa7..96852d940f2 100755 12 | --- a/build/common.sh 13 | +++ b/build/common.sh 14 | @@ -490,7 +490,7 @@ function kube::build::run_build_command_ex() { 15 | 16 | local -a docker_run_opts=( 17 | "--name=${container_name}" 18 | - "--user=$(id -u):$(id -g)" 19 | + "--user=root" 20 | "--hostname=${HOSTNAME}" 21 | "${DOCKER_MOUNT_ARGS[@]}" 22 | ) 23 | 24 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 25 | From: Shiming Zhang 26 | Date: Wed, 28 Jul 2021 17:37:59 +0800 27 | Subject: [PATCH 2/2] Run docker with device kmsg 28 | 29 | --- 30 | build/common.sh | 1 + 31 | 1 file changed, 1 insertion(+) 32 | 33 | diff --git a/build/common.sh b/build/common.sh 34 | index 96852d940f2..48998f4a21a 100755 35 | --- a/build/common.sh 36 | +++ b/build/common.sh 37 | @@ -492,6 +492,7 @@ function kube::build::run_build_command_ex() { 38 | "--name=${container_name}" 39 | "--user=root" 40 | "--hostname=${HOSTNAME}" 41 | + "--device=/dev/kmsg" 42 | "${DOCKER_MOUNT_ARGS[@]}" 43 | ) 44 | 45 | -------------------------------------------------------------------------------- /patches/fix-test.1.16.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Shiming Zhang 3 | Date: Tue, 27 Jul 2021 15:17:40 +0800 4 | Subject: [PATCH] Fix test 5 | 6 | --- 7 | .../pkg/apis/apiextensions/helpers_test.go | 2 +- 8 | 1 file changed, 1 insertion(+), 1 deletion(-) 9 | 10 | diff --git a/staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/helpers_test.go b/staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/helpers_test.go 11 | index fbbebee6060..7acffd7eb76 100644 12 | --- a/staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/helpers_test.go 13 | +++ b/staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/helpers_test.go 14 | @@ -275,7 +275,7 @@ func TestSetCRDCondition(t *testing.T) { 15 | t.Errorf("%v expected %v, got %v", tc.name, tc.expectedcrdCondition, crd.Status.Conditions) 16 | } 17 | if crd.Status.Conditions[i].LastTransitionTime.IsZero() { 18 | - t.Errorf("%q lastTransitionTime should not be null: %v", tc.name, i, crd.Status.Conditions) 19 | + t.Errorf("%q lastTransitionTime should not be null: %v", tc.name, crd.Status.Conditions) 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /patches/no-delete-images.1.10.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Shiming Zhang 3 | Date: Thu, 22 Jul 2021 18:41:45 +0800 4 | Subject: [PATCH] No delete images 5 | 6 | --- 7 | build/lib/release.sh | 8 ++++---- 8 | 1 file changed, 4 insertions(+), 4 deletions(-) 9 | 10 | diff --git a/build/lib/release.sh b/build/lib/release.sh 11 | index b0a45b4e620..3af72ecd26e 100644 12 | --- a/build/lib/release.sh 13 | +++ b/build/lib/release.sh 14 | @@ -374,11 +374,11 @@ function kube::release::create_docker_images_for_server() { 15 | "${DOCKER[@]}" rmi "${release_docker_image_tag}" 2>/dev/null || true 16 | "${DOCKER[@]}" tag "${docker_image_tag}" "${release_docker_image_tag}" 2>/dev/null 17 | fi 18 | - else 19 | + # else 20 | # not a release 21 | - kube::log::status "Deleting docker image ${docker_image_tag}" 22 | - "${DOCKER[@]}" rmi ${docker_image_tag} &>/dev/null || true 23 | - "${DOCKER[@]}" rmi ${deprecated_image_tag} &>/dev/null || true 24 | + # kube::log::status "Deleting docker image ${docker_image_tag}" 25 | + # "${DOCKER[@]}" rmi ${docker_image_tag} &>/dev/null || true 26 | + # "${DOCKER[@]}" rmi ${deprecated_image_tag} &>/dev/null || true 27 | fi 28 | ) & 29 | done 30 | -------------------------------------------------------------------------------- /patches/no-delete-images.1.12.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Shiming Zhang 3 | Date: Thu, 22 Jul 2021 18:41:45 +0800 4 | Subject: [PATCH] No delete images 5 | 6 | --- 7 | build/lib/release.sh | 8 ++++---- 8 | 1 file changed, 4 insertions(+), 4 deletions(-) 9 | 10 | diff --git a/build/lib/release.sh b/build/lib/release.sh 11 | index 1275e6e1d96..ef7a5838e73 100644 12 | --- a/build/lib/release.sh 13 | +++ b/build/lib/release.sh 14 | @@ -374,11 +374,11 @@ function kube::release::create_docker_images_for_server() { 15 | "${DOCKER[@]}" rmi "${release_docker_image_tag}" 2>/dev/null || true 16 | "${DOCKER[@]}" tag "${docker_image_tag}" "${release_docker_image_tag}" 2>/dev/null 17 | fi 18 | - else 19 | + # else 20 | # not a release 21 | - kube::log::status "Deleting docker image ${docker_image_tag}" 22 | - "${DOCKER[@]}" rmi "${docker_image_tag}" &>/dev/null || true 23 | - "${DOCKER[@]}" rmi "${deprecated_image_tag}" &>/dev/null || true 24 | + # kube::log::status "Deleting docker image ${docker_image_tag}" 25 | + # "${DOCKER[@]}" rmi "${docker_image_tag}" &>/dev/null || true 26 | + # "${DOCKER[@]}" rmi "${deprecated_image_tag}" &>/dev/null || true 27 | fi 28 | ) & 29 | done 30 | -------------------------------------------------------------------------------- /patches/no-delete-images.1.15.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Shiming Zhang 3 | Date: Thu, 22 Jul 2021 18:41:45 +0800 4 | Subject: [PATCH] No delete images 5 | 6 | --- 7 | build/lib/release.sh | 6 +++--- 8 | 1 file changed, 3 insertions(+), 3 deletions(-) 9 | 10 | diff --git a/build/lib/release.sh b/build/lib/release.sh 11 | index 9e0de70ffe5..b28c38fcb56 100644 12 | --- a/build/lib/release.sh 13 | +++ b/build/lib/release.sh 14 | @@ -408,10 +408,10 @@ EOF 15 | "${DOCKER[@]}" rmi "${release_docker_image_tag}" 2>/dev/null || true 16 | "${DOCKER[@]}" tag "${docker_image_tag}" "${release_docker_image_tag}" 2>/dev/null 17 | fi 18 | - else 19 | + # else 20 | # not a release 21 | - kube::log::status "Deleting docker image ${docker_image_tag}" 22 | - "${DOCKER[@]}" rmi "${docker_image_tag}" &>/dev/null || true 23 | + # kube::log::status "Deleting docker image ${docker_image_tag}" 24 | + # "${DOCKER[@]}" rmi "${docker_image_tag}" &>/dev/null || true 25 | fi 26 | ) & 27 | done 28 | -------------------------------------------------------------------------------- /patches/no-delete-images.1.24.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Shiming Zhang 3 | Date: Thu, 22 Jul 2021 18:41:45 +0800 4 | Subject: [PATCH] No delete images 5 | 6 | --- 7 | build/lib/release.sh | 4 ++-- 8 | 1 file changed, 2 insertions(+), 2 deletions(-) 9 | 10 | diff --git a/build/lib/release.sh b/build/lib/release.sh 11 | index ef262b5ed04..2130f1e239a 100644 12 | --- a/build/lib/release.sh 13 | +++ b/build/lib/release.sh 14 | @@ -364,8 +364,8 @@ function kube::release::create_docker_images_for_server() { 15 | rm -rf "${docker_build_path}" 16 | ln "${binary_file_path}.tar" "${images_dir}/" 17 | 18 | - kube::log::status "Deleting docker image ${docker_image_tag}" 19 | - "${DOCKER[@]}" rmi "${docker_image_tag}" &>/dev/null || true 20 | + # kube::log::status "Deleting docker image ${docker_image_tag}" 21 | + # "${DOCKER[@]}" rmi "${docker_image_tag}" &>/dev/null || true 22 | ) & 23 | done 24 | 25 | -------------------------------------------------------------------------------- /patches/nokmem.1.13.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Shiming Zhang 3 | Date: Tue, 17 Aug 2021 10:00:45 +0800 4 | Subject: [PATCH] Disabled kmem 5 | 6 | --- 7 | .../runc/libcontainer/cgroups/fs/memory.go | 42 ++----------------- 8 | 1 file changed, 4 insertions(+), 38 deletions(-) 9 | 10 | diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/memory.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/memory.go 11 | index ad395a5d621..72db8679687 100644 12 | --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/memory.go 13 | +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/memory.go 14 | @@ -4,24 +4,20 @@ package fs 15 | 16 | import ( 17 | "bufio" 18 | + "errors" 19 | "fmt" 20 | - "io/ioutil" 21 | "os" 22 | "path/filepath" 23 | "strconv" 24 | "strings" 25 | - "syscall" // only for Errno 26 | 27 | "github.com/opencontainers/runc/libcontainer/cgroups" 28 | "github.com/opencontainers/runc/libcontainer/configs" 29 | - 30 | - "golang.org/x/sys/unix" 31 | ) 32 | 33 | const ( 34 | - cgroupKernelMemoryLimit = "memory.kmem.limit_in_bytes" 35 | - cgroupMemorySwapLimit = "memory.memsw.limit_in_bytes" 36 | - cgroupMemoryLimit = "memory.limit_in_bytes" 37 | + cgroupMemorySwapLimit = "memory.memsw.limit_in_bytes" 38 | + cgroupMemoryLimit = "memory.limit_in_bytes" 39 | ) 40 | 41 | type MemoryGroup struct { 42 | @@ -68,41 +64,11 @@ func (s *MemoryGroup) Apply(d *cgroupData) (err error) { 43 | } 44 | 45 | func EnableKernelMemoryAccounting(path string) error { 46 | - // Check if kernel memory is enabled 47 | - // We have to limit the kernel memory here as it won't be accounted at all 48 | - // until a limit is set on the cgroup and limit cannot be set once the 49 | - // cgroup has children, or if there are already tasks in the cgroup. 50 | - for _, i := range []int64{1, -1} { 51 | - if err := setKernelMemory(path, i); err != nil { 52 | - return err 53 | - } 54 | - } 55 | return nil 56 | } 57 | 58 | func setKernelMemory(path string, kernelMemoryLimit int64) error { 59 | - if path == "" { 60 | - return fmt.Errorf("no such directory for %s", cgroupKernelMemoryLimit) 61 | - } 62 | - if !cgroups.PathExists(filepath.Join(path, cgroupKernelMemoryLimit)) { 63 | - // kernel memory is not enabled on the system so we should do nothing 64 | - return nil 65 | - } 66 | - if err := ioutil.WriteFile(filepath.Join(path, cgroupKernelMemoryLimit), []byte(strconv.FormatInt(kernelMemoryLimit, 10)), 0700); err != nil { 67 | - // Check if the error number returned by the syscall is "EBUSY" 68 | - // The EBUSY signal is returned on attempts to write to the 69 | - // memory.kmem.limit_in_bytes file if the cgroup has children or 70 | - // once tasks have been attached to the cgroup 71 | - if pathErr, ok := err.(*os.PathError); ok { 72 | - if errNo, ok := pathErr.Err.(syscall.Errno); ok { 73 | - if errNo == unix.EBUSY { 74 | - return fmt.Errorf("failed to set %s, because either tasks have already joined this cgroup or it has children", cgroupKernelMemoryLimit) 75 | - } 76 | - } 77 | - } 78 | - return fmt.Errorf("failed to write %v to %v: %v", kernelMemoryLimit, cgroupKernelMemoryLimit, err) 79 | - } 80 | - return nil 81 | + return errors.New("kernel memory accounting disabled in this runc build") 82 | } 83 | 84 | func setMemoryAndSwap(path string, cgroup *configs.Cgroup) error { 85 | -------------------------------------------------------------------------------- /patches/nokmem.1.20.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Shiming Zhang 3 | Date: Mon, 16 Aug 2021 19:14:44 +0800 4 | Subject: [PATCH] Disabled kmem 5 | 6 | --- 7 | .../opencontainers/runc/libcontainer/cgroups/fs/kmem.go | 2 +- 8 | .../runc/libcontainer/cgroups/fs/kmem_disabled.go | 2 +- 9 | 2 files changed, 2 insertions(+), 2 deletions(-) 10 | 11 | diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/kmem.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/kmem.go 12 | index 8d97a6791a4..8935e811742 100644 13 | --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/kmem.go 14 | +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/kmem.go 15 | @@ -1,4 +1,4 @@ 16 | -// +build linux,!nokmem 17 | +// +build linux,ignore 18 | 19 | package fs 20 | 21 | diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/kmem_disabled.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/kmem_disabled.go 22 | index ac290fd7a02..c8fbdaa3128 100644 23 | --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/kmem_disabled.go 24 | +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/kmem_disabled.go 25 | @@ -1,4 +1,4 @@ 26 | -// +build linux,nokmem 27 | +// +build linux 28 | 29 | package fs 30 | 31 | -------------------------------------------------------------------------------- /patches/update-kube-proxy-iptables.1.18.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: cyclinder 3 | Date: Fri, 22 Dec 2023 14:23:10 +0800 4 | Subject: [PATCH] kube-proxy: update iptables version 5 | 6 | --- 7 | build/BUILD | 2 +- 8 | build/common.sh | 4 ++-- 9 | 2 files changed, 3 insertions(+), 3 deletions(-) 10 | 11 | diff --git a/build/BUILD b/build/BUILD 12 | index 70e3874b441..4c67a178517 100644 13 | --- a/build/BUILD 14 | +++ b/build/BUILD 15 | @@ -42,7 +42,7 @@ DOCKERIZED_BINARIES = { 16 | "target": "//cmd/kube-scheduler:kube-scheduler", 17 | }, 18 | "kube-proxy": { 19 | - "base": "@debian-iptables-{ARCH}//image", 20 | + "base": "@distroless-iptables//image", 21 | "target": "//cmd/kube-proxy:kube-proxy", 22 | }, 23 | } 24 | diff --git a/build/common.sh b/build/common.sh 25 | index 9cd95b5af51..13c15466c39 100755 26 | --- a/build/common.sh 27 | +++ b/build/common.sh 28 | @@ -95,14 +95,14 @@ readonly KUBE_CONTAINER_RSYNC_PORT=8730 29 | kube::build::get_docker_wrapped_binaries() { 30 | local arch=$1 31 | local debian_base_version=v2.1.3 32 | - local debian_iptables_version=v12.1.2 33 | + local distroless_iptables_version=v0.4.2 34 | ### If you change any of these lists, please also update DOCKERIZED_BINARIES 35 | ### in build/BUILD. And kube::golang::server_image_targets 36 | local targets=( 37 | "kube-apiserver,${KUBE_BASE_IMAGE_REGISTRY}/debian-base-${arch}:${debian_base_version}" 38 | "kube-controller-manager,${KUBE_BASE_IMAGE_REGISTRY}/debian-base-${arch}:${debian_base_version}" 39 | "kube-scheduler,${KUBE_BASE_IMAGE_REGISTRY}/debian-base-${arch}:${debian_base_version}" 40 | - "kube-proxy,${KUBE_BASE_IMAGE_REGISTRY}/debian-iptables-${arch}:${debian_iptables_version}" 41 | + "kube-proxy,registry.k8s.io/build-image/distroless-iptables:${distroless_iptables_version}" 42 | ) 43 | 44 | echo "${targets[@]}" 45 | -------------------------------------------------------------------------------- /rpm/kubeadm/10-kubeadm.conf: -------------------------------------------------------------------------------- 1 | # Note: This dropin only works with kubeadm and kubelet v1.11+ 2 | [Service] 3 | Environment="KUBELET_KUBECONFIG_ARGS=--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf" 4 | Environment="KUBELET_CONFIG_ARGS=--config=/var/lib/kubelet/config.yaml" 5 | # This is a file that "kubeadm init" and "kubeadm join" generates at runtime, populating the KUBELET_KUBEADM_ARGS variable dynamically 6 | EnvironmentFile=-/var/lib/kubelet/kubeadm-flags.env 7 | # This is a file that the user can use for overrides of the kubelet args as a last resort. Preferably, the user should use 8 | # the .NodeRegistration.KubeletExtraArgs object in the configuration files instead. KUBELET_EXTRA_ARGS should be sourced from this file. 9 | EnvironmentFile=-/etc/sysconfig/kubelet 10 | ExecStart= 11 | ExecStart=/usr/bin/kubelet $KUBELET_KUBECONFIG_ARGS $KUBELET_CONFIG_ARGS $KUBELET_KUBEADM_ARGS $KUBELET_EXTRA_ARGS 12 | -------------------------------------------------------------------------------- /rpm/kubeadm/kubeadm.spec: -------------------------------------------------------------------------------- 1 | Name: kubeadm 2 | Version: %{_version} 3 | Release: %{_release} 4 | Summary: Command-line utility for administering a Kubernetes cluster. 5 | License: ASL 2.0 6 | 7 | URL: https://kubernetes.io 8 | Source0: %{name}-%{version}.tar.gz 9 | 10 | BuildRequires: systemd 11 | 12 | Requires: kubelet >= %{_version} 13 | Requires: kubectl >= %{_version} 14 | Requires: kubernetes-cni >= 0.8.6 15 | Requires: cri-tools >= 1.13.0 16 | 17 | %description 18 | Command-line utility for administering a Kubernetes cluster. 19 | 20 | %prep 21 | %setup 22 | 23 | install -m 755 -d %{buildroot}%{_sysconfdir}/kubernetes/manifests/ 24 | install -m 755 -d %{buildroot}%{_unitdir}/kubelet.service.d/ 25 | install -m 755 -d %{buildroot}%{_bindir} 26 | install -p -m 755 -t %{buildroot}%{_bindir}/ kubeadm 27 | install -p -m 644 -t %{buildroot}%{_unitdir}/kubelet.service.d/ 10-kubeadm.conf 28 | 29 | %files 30 | %{_bindir}/kubeadm 31 | %{_unitdir}/kubelet.service.d/10-kubeadm.conf 32 | -------------------------------------------------------------------------------- /rpm/kubectl/kubectl.spec: -------------------------------------------------------------------------------- 1 | Name: kubectl 2 | Version: %{_version} 3 | Release: %{_release} 4 | Summary: Command-line utility for interacting with a Kubernetes cluster. 5 | License: ASL 2.0 6 | 7 | URL: https://kubernetes.io 8 | Source0: %{name}-%{version}.tar.gz 9 | 10 | BuildRequires: systemd 11 | 12 | %description 13 | Command-line utility for interacting with a Kubernetes cluster. 14 | 15 | %prep 16 | %setup 17 | 18 | install -m 755 -d %{buildroot}%{_bindir} 19 | install -p -m 755 -t %{buildroot}%{_bindir}/ kubectl 20 | 21 | %files 22 | %{_bindir}/kubectl 23 | -------------------------------------------------------------------------------- /rpm/kubelet/kubelet.env: -------------------------------------------------------------------------------- 1 | KUBELET_EXTRA_ARGS= 2 | -------------------------------------------------------------------------------- /rpm/kubelet/kubelet.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=kubelet: The Kubernetes Node Agent 3 | Documentation=https://kubernetes.io/docs/ 4 | Wants=network-online.target 5 | After=network-online.target 6 | 7 | [Service] 8 | ExecStart=/usr/bin/kubelet 9 | Restart=always 10 | StartLimitInterval=0 11 | RestartSec=10 12 | 13 | [Install] 14 | WantedBy=multi-user.target 15 | -------------------------------------------------------------------------------- /rpm/kubelet/kubelet.spec: -------------------------------------------------------------------------------- 1 | Name: kubelet 2 | Version: %{_version} 3 | Release: %{_release} 4 | Summary: Container cluster management 5 | License: ASL 2.0 6 | 7 | URL: https://kubernetes.io 8 | Source0: %{name}-%{version}.tar.gz 9 | 10 | BuildRequires: systemd 11 | 12 | Requires: iptables >= 1.4.21 13 | Requires: kubernetes-cni >= 0.8.6 14 | Requires: socat 15 | Requires: util-linux 16 | Requires: ethtool 17 | Requires: iproute 18 | Requires: ebtables 19 | Requires: conntrack 20 | 21 | %description 22 | The node agent of Kubernetes, the container cluster manager. 23 | 24 | %prep 25 | %setup 26 | 27 | install -m 755 -d %{buildroot}%{_unitdir} 28 | install -m 755 -d %{buildroot}%{_unitdir}/kubelet.service.d/ 29 | install -m 755 -d %{buildroot}%{_bindir} 30 | install -m 755 -d %{buildroot}/var/lib/kubelet/ 31 | install -p -m 755 -t %{buildroot}%{_bindir}/ kubelet 32 | install -p -m 644 -t %{buildroot}%{_unitdir}/ kubelet.service 33 | install -m 755 -d %{buildroot}%{_sysconfdir}/sysconfig/ 34 | install -p -m 644 -T kubelet.env %{buildroot}%{_sysconfdir}/sysconfig/kubelet 35 | 36 | 37 | 38 | %files 39 | %{_bindir}/kubelet 40 | %{_unitdir}/kubelet.service 41 | 42 | %config(noreplace) %{_sysconfdir}/sysconfig/kubelet 43 | --------------------------------------------------------------------------------