Skip to content
This repository was archived by the owner on Mar 22, 2018. It is now read-only.

Commit 5b8c213

Browse files
committed
Merge branch 'master' of file:///Users/dims/go/src/github.com/dims/k8s-keystone-auth into add-k8s-keystone-auth-repo
2 parents 54d4ea4 + 9195797 commit 5b8c213

10 files changed

Lines changed: 1016 additions & 0 deletions

File tree

cluster/images/webhook/Dockerfile

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
FROM ubuntu:16.04
2+
MAINTAINER Saverio Proto <[email protected]>
3+
RUN apt-get update && \
4+
apt-get install -y software-properties-common
5+
RUN add-apt-repository -y ppa:masterminds/glide
6+
RUN apt-get update && \
7+
apt-get install -y glide git build-essential golang && \
8+
apt-get clean && \
9+
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
10+
RUN git clone https://github.com/dims/k8s-keystone-auth
11+
WORKDIR k8s-keystone-auth
12+
RUN make depend && make build
13+
EXPOSE 8443
14+
CMD ./bin/k8s-keystone-auth --tls-cert-file ${API_SERVER_CERT} --tls-private-key-file ${API_SERVER_KEY} --keystone-url ${OPENSTACK_KEYSTONE_URL}
15+

cmd/k8s-keystone-auth/main.go

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
Licensed under the Apache License, Version 2.0 (the "License");
3+
you may not use this file except in compliance with the License.
4+
You may obtain a copy of the License at
5+
6+
http://www.apache.org/licenses/LICENSE-2.0
7+
8+
Unless required by applicable law or agreed to in writing, software
9+
distributed under the License is distributed on an "AS IS" BASIS,
10+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
See the License for the specific language governing permissions and
12+
limitations under the License.
13+
*/
14+
15+
package main
16+
17+
import (
18+
"flag"
19+
"log"
20+
"net/http"
21+
22+
"github.com/dims/k8s-keystone-auth/pkg/authenticator/token/keystone"
23+
"github.com/dims/k8s-keystone-auth/pkg/identity/webhook"
24+
"k8s.io/apiserver/pkg/authentication/authenticator"
25+
"k8s.io/apiserver/pkg/authorization/authorizer"
26+
)
27+
28+
func webhookServer(authenticator authenticator.Token, authorizer authorizer.Authorizer) http.Handler {
29+
return &webhook.WebhookHandler{
30+
Authenticator: authenticator,
31+
Authorizer: authorizer,
32+
}
33+
}
34+
35+
var (
36+
listenAddr string
37+
tlsCertFile string
38+
tlsPrivateKey string
39+
keystoneURL string
40+
keystoneCaFile string
41+
policyFile string
42+
)
43+
44+
func main() {
45+
flag.StringVar(&listenAddr, "listen", "localhost:8443", "<address>:<port> to listen on")
46+
flag.StringVar(&tlsCertFile, "tls-cert-file", "", "File containing the default x509 Certificate for HTTPS.")
47+
flag.StringVar(&tlsPrivateKey, "tls-private-key-file", "", "File containing the default x509 private key matching --tls-cert-file.")
48+
flag.StringVar(&keystoneURL, "keystone-url", "http://localhost/identity/v3/", "URL for the OpenStack Keystone API")
49+
flag.StringVar(&keystoneCaFile, "keystone-ca-file", "", "File containing the certificate authority for Keystone Service.")
50+
flag.StringVar(&policyFile, "keystone-policy-file", "", "File containing the policy.")
51+
flag.Parse()
52+
53+
if tlsCertFile == "" || tlsPrivateKey == "" {
54+
log.Fatal("Please specify --tls-cert-file and --tls-private-key-file arguments.")
55+
}
56+
if policyFile == "" {
57+
log.Printf("Argument --keystone-policy-file missing. Only keystone authentication will work. Use RBAC for authorization.")
58+
}
59+
60+
authentication_handler, err := keystone.NewKeystoneAuthenticator(keystoneURL, keystoneCaFile)
61+
if err != nil {
62+
log.Fatal(err.Error())
63+
}
64+
65+
authorization_handler, err := keystone.NewKeystoneAuthorizer(keystoneURL, keystoneCaFile, policyFile)
66+
if err != nil {
67+
log.Fatal(err.Error())
68+
}
69+
70+
http.Handle("/webhook", webhookServer(authentication_handler, authorization_handler))
71+
log.Println("Starting webhook..")
72+
log.Fatal(
73+
http.ListenAndServeTLS(":8443",
74+
tlsCertFile,
75+
tlsPrivateKey,
76+
nil))
77+
}

examples/webhook/policy.json

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
[
2+
{
3+
"resource": {
4+
"verb": "*",
5+
"resource": "*",
6+
"version": "*",
7+
"namespace": "*"
8+
},
9+
"match": {
10+
"type": "role",
11+
"value": "*"
12+
}
13+
},
14+
{
15+
"resource": {
16+
"verb": "*",
17+
"resource": "*",
18+
"version": "*",
19+
"namespace": "*"
20+
},
21+
"match": {
22+
"type": "group",
23+
"value": "*"
24+
}
25+
},
26+
{
27+
"nonresource": {
28+
"verb": "*",
29+
"path": "*"
30+
},
31+
"match": {
32+
"type": "role",
33+
"value": "*"
34+
}
35+
},
36+
{
37+
"nonresource": {
38+
"verb": "*",
39+
"path": "*"
40+
},
41+
"match": {
42+
"type": "group",
43+
"value": "*"
44+
}
45+
}
46+
]
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
---
2+
apiVersion: v1
3+
kind: Pod
4+
metadata:
5+
annotations:
6+
scheduler.alpha.kubernetes.io/critical-pod: ""
7+
creationTimestamp: null
8+
labels:
9+
component: k8s-keystone-auth
10+
tier: control-plane
11+
name: k8s-keystone-auth
12+
namespace: kube-system
13+
spec:
14+
containers:
15+
- command:
16+
- ./bin/k8s-keystone-auth
17+
- --tls-cert-file
18+
- /etc/kubernetes/pki/apiserver.crt
19+
- --tls-private-key-file
20+
- /etc/kubernetes/pki/apiserver.key
21+
- --keystone-url
22+
- https://mykeystone.com:5000/v3
23+
image: k8s-keystone-auth
24+
imagePullPolicy: Always
25+
#livenessProbe:
26+
# failureThreshold: 8
27+
# httpGet:
28+
# host: 127.0.0.1
29+
# path: /healthz
30+
# port: 6443
31+
# scheme: HTTPS
32+
# initialDelaySeconds: 15
33+
# timeoutSeconds: 15
34+
name: k8s-keystone-auth
35+
resources:
36+
requests:
37+
cpu: 250m
38+
volumeMounts:
39+
- mountPath: /etc/kubernetes/pki
40+
name: k8s-certs
41+
readOnly: true
42+
- mountPath: /etc/ssl/certs
43+
name: ca-certs
44+
readOnly: true
45+
hostNetwork: true
46+
volumes:
47+
- hostPath:
48+
path: /etc/kubernetes/pki
49+
type: DirectoryOrCreate
50+
name: k8s-certs
51+
- hostPath:
52+
path: /etc/ssl/certs
53+
type: DirectoryOrCreate
54+
name: ca-certs
55+
status: {}
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/*
2+
Copyright 2017 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package keystone
18+
19+
import (
20+
"encoding/json"
21+
"errors"
22+
"io/ioutil"
23+
24+
"github.com/golang/glog"
25+
"github.com/gophercloud/gophercloud"
26+
27+
"k8s.io/apiserver/pkg/authentication/user"
28+
)
29+
30+
// KeystoneAuthenticator contacts openstack keystone to validate user's token passed in the request.
31+
// The keystone endpoint is passed during apiserver startup
32+
type KeystoneAuthenticator struct {
33+
authURL string
34+
client *gophercloud.ServiceClient
35+
}
36+
37+
// AuthenticatePassword checks the token via Keystone call
38+
func (keystoneAuthenticator *KeystoneAuthenticator) AuthenticateToken(token string) (user.Info, bool, error) {
39+
40+
// We can use the Keystone GET /v3/auth/tokens API to validate the token
41+
// and get information about the user as well
42+
// http://git.openstack.org/cgit/openstack/keystone/tree/api-ref/source/v3/authenticate-v3.inc#n437
43+
// https://developer.openstack.org/api-ref/identity/v3/?expanded=validate-and-show-information-for-token-detail
44+
request_opts := gophercloud.RequestOpts{
45+
MoreHeaders: map[string]string{
46+
"X-Auth-Token": token,
47+
"X-Subject-Token": token,
48+
},
49+
}
50+
url := keystoneAuthenticator.client.ServiceURL("auth", "tokens")
51+
response, err := keystoneAuthenticator.client.Request("GET", url, &request_opts)
52+
if err != nil {
53+
glog.V(4).Info("Failed: bad response from API call: %v", err)
54+
return nil, false, errors.New("Failed to authenticate")
55+
}
56+
57+
defer response.Body.Close()
58+
bodyBytes, err := ioutil.ReadAll(response.Body)
59+
if err != nil {
60+
glog.V(4).Infof("Cannot get HTTP response body from keystone token validate: %v", err)
61+
return nil, false, errors.New("Failed to authenticate")
62+
}
63+
64+
obj := struct {
65+
Token struct {
66+
User struct {
67+
Id string `json:"id"`
68+
Name string `json:"name"`
69+
} `json:"user"`
70+
Project struct {
71+
Id string `json:"id"`
72+
Name string `json:"name"`
73+
} `json:"project"`
74+
Roles []struct {
75+
Name string `json:"name"`
76+
} `json:"roles"`
77+
} `json:"token"`
78+
}{}
79+
80+
err = json.Unmarshal(bodyBytes, &obj)
81+
if err != nil {
82+
glog.V(4).Infof("Cannot unmarshal response: %v", err)
83+
return nil, false, errors.New("Failed to authenticate")
84+
}
85+
86+
var roles []string
87+
if obj.Token.Roles != nil && len(obj.Token.Roles) > 0 {
88+
roles = make([]string, len(obj.Token.Roles))
89+
for i := 0; i < len(obj.Token.Roles); i++ {
90+
roles[i] = obj.Token.Roles[i].Name
91+
}
92+
} else {
93+
roles = make([]string, 0)
94+
}
95+
96+
extra := map[string][]string{
97+
"alpha.kubernetes.io/identity/roles": roles,
98+
"alpha.kubernetes.io/identity/project/id": []string{obj.Token.Project.Id},
99+
"alpha.kubernetes.io/identity/project/name": []string{obj.Token.Project.Name},
100+
}
101+
102+
authenticated_user := &user.DefaultInfo{
103+
Name: obj.Token.User.Name,
104+
UID: obj.Token.User.Id,
105+
Groups: []string{obj.Token.Project.Id},
106+
Extra: extra,
107+
}
108+
109+
return authenticated_user, true, nil
110+
}

0 commit comments

Comments
 (0)