├── go.mod ├── config └── job.yaml ├── cmd └── oidc │ └── main.go ├── go.sum ├── README.md ├── .github └── workflows │ └── kind-oidc.yml └── LICENSE /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/mattmoor/kind-oidc 2 | 3 | go 1.17 4 | 5 | require github.com/coreos/go-oidc/v3 v3.1.0 6 | 7 | require ( 8 | github.com/golang/protobuf v1.2.0 // indirect 9 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 // indirect 10 | golang.org/x/net v0.0.0-20200505041828-1ed23360d12c // indirect 11 | golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect 12 | google.golang.org/appengine v1.4.0 // indirect 13 | gopkg.in/square/go-jose.v2 v2.5.1 // indirect 14 | ) 15 | -------------------------------------------------------------------------------- /config/job.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: batch/v1 2 | kind: Job 3 | metadata: 4 | name: check-oidc 5 | spec: 6 | template: 7 | spec: 8 | restartPolicy: Never 9 | automountServiceAccountToken: false 10 | containers: 11 | - name: check-oidc 12 | image: ko://github.com/mattmoor/kind-oidc/cmd/oidc 13 | volumeMounts: 14 | - name: oidc-info 15 | mountPath: /var/run/kind-oidc 16 | 17 | volumes: 18 | - name: oidc-info 19 | projected: 20 | sources: 21 | - serviceAccountToken: 22 | path: token 23 | expirationSeconds: 600 # Use as short-lived as possible. 24 | audience: kind-oidc 25 | - configMap: 26 | name: kube-root-ca.crt 27 | items: 28 | - key: ca.crt 29 | path: ca.crt 30 | mode: 0666 31 | -------------------------------------------------------------------------------- /cmd/oidc/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021 Chainguard, Inc. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | package main 7 | 8 | import ( 9 | "context" 10 | "crypto/x509" 11 | "encoding/base64" 12 | "encoding/json" 13 | "fmt" 14 | "log" 15 | "net/http" 16 | "os" 17 | "strings" 18 | 19 | "github.com/coreos/go-oidc/v3/oidc" 20 | ) 21 | 22 | func extractIssuer(token string) (string, error) { 23 | parts := strings.Split(token, ".") 24 | if len(parts) < 2 { 25 | return "", fmt.Errorf("oidc: malformed jwt, expected 3 parts got %d", len(parts)) 26 | } 27 | raw, err := base64.RawURLEncoding.DecodeString(parts[1]) 28 | if err != nil { 29 | return "", fmt.Errorf("oidc: malformed jwt payload: %w", err) 30 | } 31 | var payload struct { 32 | Issuer string `json:"iss"` 33 | } 34 | 35 | if err := json.Unmarshal(raw, &payload); err != nil { 36 | return "", fmt.Errorf("oidc: failed to unmarshal claims: %w", err) 37 | } 38 | return payload.Issuer, nil 39 | } 40 | 41 | func main() { 42 | const ( 43 | path = "/var/run/kind-oidc/token" 44 | k8sCA = "/var/run/kind-oidc/ca.crt" 45 | ) 46 | 47 | // Add the Kubernetes cluster's CA to the system CA pool, and to 48 | // the default transport. 49 | rootCAs, _ := x509.SystemCertPool() 50 | if rootCAs == nil { 51 | rootCAs = x509.NewCertPool() 52 | } 53 | certs, err := os.ReadFile(k8sCA) 54 | if err != nil { 55 | log.Fatalf("Failed to append %q to RootCAs: %v", k8sCA, err) 56 | } 57 | if ok := rootCAs.AppendCertsFromPEM(certs); !ok { 58 | log.Println("No certs appended, using system certs only") 59 | } 60 | t := http.DefaultTransport.(*http.Transport).Clone() 61 | t.TLSClientConfig.RootCAs = rootCAs 62 | http.DefaultTransport = t 63 | 64 | auth, err := os.ReadFile(path) 65 | if err != nil { 66 | log.Fatalf("Unable to read %q: %v", path, err) 67 | } 68 | 69 | issuer, err := extractIssuer(string(auth)) 70 | if err != nil { 71 | log.Fatalf("Unable to extract issuer: %v", err) 72 | } 73 | 74 | // Verify the token before we trust anything about it. 75 | provider, err := oidc.NewProvider(context.Background(), issuer) 76 | if err != nil { 77 | log.Fatalf("Unable to instantiate OIDC provider: %v", err) 78 | } 79 | verifier := provider.Verifier(&oidc.Config{ClientID: "kind-oidc"}) 80 | _, err = verifier.Verify(context.Background(), string(auth)) 81 | if err != nil { 82 | log.Fatalf("Unable to verify OIDC token: %v", err) 83 | } 84 | 85 | log.Print("OIDC token verified!") 86 | } 87 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | github.com/coreos/go-oidc/v3 v3.1.0 h1:6avEvcdvTa1qYsOZ6I5PRkSYHzpTNWgKYmaJfaYbrRw= 3 | github.com/coreos/go-oidc/v3 v3.1.0/go.mod h1:rEJ/idjfUyfkBit1eI1fvyr+64/g9dcKpAm8MJMesvo= 4 | github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= 5 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 6 | github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= 7 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 8 | github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= 9 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 10 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 11 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 12 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 13 | github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= 14 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 15 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= 16 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 17 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 18 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 19 | golang.org/x/net v0.0.0-20200505041828-1ed23360d12c h1:zJ0mtu4jCalhKg6Oaukv6iIkb+cOvDrajDH9DH46Q4M= 20 | golang.org/x/net v0.0.0-20200505041828-1ed23360d12c/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 21 | golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw= 22 | golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 23 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= 24 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 25 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 26 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 27 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 28 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 29 | google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= 30 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 31 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 32 | gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w= 33 | gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= 34 | gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= 35 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # KinD OIDC 2 | 3 | This repo contains a small example that demonstrates how to set up a KinD 4 | cluster with support for Service Account Projected Volumes. 5 | 6 | Service Account Projected Volumes are useful because they let pods project 7 | an `aud` (audience) scoped, time-limited OIDC token into the container. These 8 | short-lived, scoped tokens may be used to identify the workload against 9 | external systems (assuming the issuer/discovery URL are accessible, as they are 10 | on at least GKE and EKS clusters). 11 | 12 | The goal of this repo is to demonstrate how KinD may be used to configure a 13 | KinD cluster as a suitable e2e test environment for applications that want 14 | to send/receive this form of token. 15 | 16 | ## Key Elements 17 | 18 | When spinning up the KinD cluster, apply the following patch to enable support 19 | for the projected volumes, and to make the OIDC token's `iss` field use 20 | `https://kubernetes.default.svc` (so it is accessible on-cluster): 21 | ```yaml 22 | kubeadmConfigPatches: 23 | - | 24 | apiVersion: kubeadm.k8s.io/v1beta2 25 | kind: ClusterConfiguration 26 | metadata: 27 | name: config 28 | apiServer: 29 | extraArgs: 30 | "service-account-issuer": "https://kubernetes.default.svc" 31 | "service-account-signing-key-file": "/etc/kubernetes/pki/sa.key" 32 | "service-account-jwks-uri": "https://kubernetes.default.svc/openid/v1/jwks" 33 | "service-account-key-file": "/etc/kubernetes/pki/sa.pub" 34 | ``` 35 | 36 | By default, the discovery endpoint on the KinD cluster is locked down, but the 37 | discovery endpoint can be opened up with the following command: 38 | 39 | ```shell 40 | kubectl create clusterrolebinding oidc-reviewer \ 41 | --clusterrole=system:service-account-issuer-discovery \ 42 | --group=system:unauthenticated 43 | ``` 44 | 45 | The above is from a [great article](https://banzaicloud.com/blog/kubernetes-oidc/) 46 | which says: 47 | > To be able to fetch the public keys and validate the JWT tokens against 48 | > the Kubernetes cluster’s issuer we have to allow external unauthenticated 49 | > requests. To do this, we bind this special role with a ClusterRoleBinding 50 | > to unauthenticated users (make sure that this is safe in your environment, 51 | > but only public keys are visible on this URL) 52 | 53 | 54 | 55 | The final bit you need (for KinD) is to ensure you trust the cluster's CA 56 | in your OIDC verification logic because the issuer endpoint's TLS is not 57 | signed by a public CA on KinD clusters. This can be done with the following 58 | two snippets. 59 | 60 | Adding this to the projected volume will mount the cluster's CA certs into 61 | the container (See 62 | [KEP 1205](https://github.com/kubernetes/enhancements/blob/master/keps/sig-auth/1205-bound-service-account-tokens/README.md), 63 | thanks to @mattmoyer for the pointer!): 64 | ```yaml 65 | - configMap: 66 | name: kube-root-ca.crt 67 | items: 68 | - key: ca.crt 69 | path: ca.crt 70 | mode: 0666 71 | ``` 72 | 73 | Then this piece of code will augment the system cert pool with the CA 74 | certificates mounted above: 75 | ```go 76 | const k8sCA = "/var/run/kind-oidc/ca.crt" 77 | 78 | // Add the Kubernetes cluster's CA to the system CA pool, and to 79 | // the default transport. 80 | rootCAs, _ := x509.SystemCertPool() 81 | if rootCAs == nil { 82 | rootCAs = x509.NewCertPool() 83 | } 84 | certs, err := os.ReadFile(k8sCA) 85 | if err != nil { 86 | log.Fatalf("Failed to append %q to RootCAs: %v", k8sCA, err) 87 | } 88 | if ok := rootCAs.AppendCertsFromPEM(certs); !ok { 89 | log.Println("No certs appended, using system certs only") 90 | } 91 | 92 | // WARNING: This changes the program's default transport. If this 93 | // is undesirable, or your OIDC verification library supports passing 94 | // an HTTP transport, then favor passing `t` over setting 95 | // `http.DefaultTransport` 96 | t := http.DefaultTransport.(*http.Transport).Clone() 97 | t.TLSClientConfig.RootCAs = rootCAs 98 | http.DefaultTransport = t 99 | ``` 100 | -------------------------------------------------------------------------------- /.github/workflows/kind-oidc.yml: -------------------------------------------------------------------------------- 1 | name: KinD OIDC 2 | 3 | on: 4 | push: 5 | branches: [ 'main' ] 6 | pull_request: 7 | branches: [ 'main' ] 8 | 9 | workflow_dispatch: {} 10 | 11 | defaults: 12 | run: 13 | shell: bash 14 | working-directory: ./src/github.com/mattmoor/kind-oidc 15 | 16 | jobs: 17 | 18 | kind-oidc: 19 | name: KinD OIDC 20 | runs-on: ubuntu-latest 21 | 22 | env: 23 | # https://github.com/google/go-containerregistry/pull/125 allows insecure registry for 24 | # '*.local' hostnames. This works both for `ko` and our own tag-to-digest resolution logic, 25 | # thus allowing us to test without bypassing tag-to-digest resolution. 26 | REGISTRY_NAME: registry.local 27 | REGISTRY_PORT: 5000 28 | KO_DOCKER_REPO: registry.local:5000/knative 29 | 30 | steps: 31 | - name: Set up Go 1.17.x 32 | uses: actions/setup-go@v2 33 | with: 34 | go-version: 1.17.x 35 | 36 | - uses: imjasonh/setup-ko@v0.4 37 | 38 | - name: Check out code onto GOPATH 39 | uses: actions/checkout@v2 40 | with: 41 | path: ./src/github.com/mattmoor/kind-oidc 42 | 43 | - name: Install KinD 44 | run: | 45 | # Disable swap otherwise memory enforcement doesn't work 46 | # See: https://kubernetes.slack.com/archives/CEKK1KTN2/p1600009955324200 47 | sudo swapoff -a 48 | sudo rm -f /swapfile 49 | 50 | # Use in-memory storage to avoid etcd server timeouts. 51 | # https://kubernetes.slack.com/archives/CEKK1KTN2/p1615134111016300 52 | # https://github.com/kubernetes-sigs/kind/issues/845 53 | sudo mkdir -p /tmp/etcd 54 | sudo mount -t tmpfs tmpfs /tmp/etcd 55 | 56 | curl -Lo ./kind https://github.com/kubernetes-sigs/kind/releases/download/v0.11.1/kind-$(uname)-amd64 57 | chmod +x ./kind 58 | sudo mv kind /usr/local/bin 59 | 60 | - name: Configure KinD Cluster 61 | run: | 62 | set -x 63 | 64 | # KinD configuration. 65 | cat > kind.yaml < 127.0.0.1, to tell `ko` to publish to 116 | # local reigstry, even when pushing $REGISTRY_NAME:$REGISTRY_PORT/some/image 117 | sudo echo "127.0.0.1 $REGISTRY_NAME" | sudo tee -a /etc/hosts 118 | 119 | - name: Verify OIDC is configured 120 | run: | 121 | # From: https://banzaicloud.com/blog/kubernetes-oidc/ 122 | # To be able to fetch the public keys and validate the JWT tokens against 123 | # the Kubernetes cluster’s issuer we have to allow external unauthenticated 124 | # requests. To do this, we bind this special role with a ClusterRoleBinding 125 | # to unauthenticated users (make sure that this is safe in your environment, 126 | # but only public keys are visible on this URL) 127 | kubectl create clusterrolebinding oidc-reviewer \ 128 | --clusterrole=system:service-account-issuer-discovery \ 129 | --group=system:unauthenticated 130 | 131 | ko apply -Bf config/ 132 | 133 | kubectl wait --for=condition=Complete --timeout=90s job/check-oidc 134 | 135 | - name: Dump job output 136 | if: ${{ failure() }} 137 | run: | 138 | kubectl describe job check-oidc 139 | 140 | for ns in default; do 141 | kubectl get pods -n${ns} 142 | echo '::group:: describe' 143 | kubectl describe pods -n${ns} 144 | echo '::endgroup::' 145 | for x in $(kubectl get pods -n${ns} -oname); do 146 | echo "::group:: describe $x" 147 | kubectl describe -n${ns} $x 148 | echo '::endgroup::' 149 | echo "::group:: $x logs" 150 | kubectl logs -n${ns} $x --all-containers 151 | echo '::endgroup::' 152 | done 153 | done 154 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | --------------------------------------------------------------------------------