1
+ #! /bin/bash
2
+ #
3
+ # Copyright © 2020 Portworx
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
18
+ # USE ONLY FOR DEVELOPMENT
19
+ # Implementation of the blog: https://www.openlogic.com/blog/granting-user-access-your-kubernetes-cluster
20
+
21
+ function fail() {
22
+ echo " $1 "
23
+ exit 1
24
+ }
25
+
26
+ # run() from BATS testing system
27
+ function runorfail() {
28
+ local origFlags=" $- "
29
+ set +eET
30
+ local origIFS=" $IFS "
31
+ echo $@
32
+ output=" $( " $@ " 2>&1 ) "
33
+ if [ $? -ne 0 ]; then
34
+ fail " Failed to execute ${* } "
35
+ fi
36
+ IFS=$' \n ' lines=($output )
37
+ IFS=" $origIFS "
38
+ set " -$origFlags "
39
+ }
40
+
41
+ # Creats a user in Kubernetes only. Use createUserKubeconfig() instead to create a full
42
+ # kubeconfig for the new user.
43
+ function createUser() {
44
+ local username=" $1 "
45
+ local location=" $2 "
46
+
47
+ runorfail openssl req -new -newkey rsa:4096 -nodes \
48
+ -keyout ${location} /${username} -k8s.key \
49
+ -out ${location} /${username} -k8s.csr \
50
+ -subj " /CN=${username} /O=${ORGANIZATION} "
51
+
52
+ cat << EOF | kubectl --context=$CONTEXT apply -f -
53
+ apiVersion: certificates.k8s.io/v1beta1
54
+ kind: CertificateSigningRequest
55
+ metadata:
56
+ name: ${username} -access
57
+ spec:
58
+ request: $( cat ${location} /${username} -k8s.csr | base64 | tr -d ' \n' )
59
+ usages:
60
+ - client auth
61
+ EOF
62
+ if [ $? -ne 0 ] ; then
63
+ fail " Failed to create certificate signing request in Kubernetes"
64
+ fi
65
+
66
+ runorfail kubectl --context=$CONTEXT certificate approve ${username} -access
67
+ kubectl --context=$CONTEXT get csr ${username} -access \
68
+ -o jsonpath=' {.status.certificate}' | base64 --decode > ${location} /${username} -kubeconfig.crt
69
+ if [ $? -ne 0 ] ; then
70
+ fail " Failed to get certificate for user"
71
+ fi
72
+ }
73
+
74
+ # Creates a new Kubernetes user only able to access their namespace with the
75
+ # same name. The kubeconfig for this user must be passed in.
76
+ function createUserKubeconfig() {
77
+ local user=" $1 "
78
+ local location=" $2 "
79
+ local cafile=" $3 "
80
+ local kubeconfig=" ${location} /${user} -kubeconfig.conf"
81
+
82
+ echo " >>> Registering ${user} "
83
+
84
+ # create certs for user
85
+ createUser " $user " " $location "
86
+
87
+ # Create namespace
88
+ if ! kubectl --context=$CONTEXT get namespace ${NAMESPACE} > /dev/null 2>&1 ; then
89
+ runorfail kubectl create namespace ${NAMESPACE} --context=$CONTEXT
90
+ fi
91
+
92
+ # Enable user to use their namespace
93
+ runorfail kubectl create rolebinding ${user} -admin \
94
+ --context=$CONTEXT \
95
+ --namespace=${NAMESPACE} \
96
+ --clusterrole=admin \
97
+ --user=${user}
98
+
99
+ # Enable token to have API access
100
+ runorfail kubectl create rolebinding default-access-rest \
101
+ --context=$CONTEXT \
102
+ --namespace=${NAMESPACE} \
103
+ --clusterrole=admin \
104
+ --serviceaccount=${user} :default
105
+
106
+ echo " >>> Creating ${kubeconfig} "
107
+
108
+ # Create config for user
109
+ kubectl config set-cluster $cluster \
110
+ --server=$address \
111
+ --certificate-authority=$cafile \
112
+ --embed-certs=true \
113
+ --kubeconfig=${kubeconfig}
114
+ kubectl config set-credentials \
115
+ ${user} \
116
+ --client-certificate=${location} /${user} -kubeconfig.crt \
117
+ --client-key=${location} /${user} -k8s.key \
118
+ --embed-certs \
119
+ --kubeconfig=${kubeconfig}
120
+ kubectl --kubeconfig=${kubeconfig} config set-context ${user} \
121
+ --cluster=${cluster} \
122
+ --user=${user} \
123
+ --namespace=${NAMESPACE}
124
+ kubectl --kubeconfig=${kubeconfig} config use-context ${user}
125
+
126
+ echo " "
127
+ echo " >>> Kubeconfig ready: ${kubeconfig} "
128
+ }
129
+
130
+ function usage() {
131
+ echo "
132
+ Creates a new Kubernetes user and creating a new kubeconfig
133
+
134
+ Usage:
135
+ kubectl pxc useradd [flags]
136
+
137
+ Flags:
138
+ -h, --help help for create
139
+ --name Name of user
140
+ --namespace Specify the new namespace for the user (default: user name)
141
+ --organization Name of the organization (default: portworx)
142
+ --px-secret Name of secret to contain the Portworx token (default: px-user-token)
143
+ --outdir Directory where to place the created files (default: .)
144
+ --kubeconfig Specify the kubeconfig to use (optional)
145
+ --context Specify the context to use (optional)
146
+ "
147
+ exit 1
148
+ }
149
+
150
+ parsed=$( getopt -o h -n " kubectl pxc useradd" --long name:,namespace:,help,organization:,px-secret:,outdir:,context:,kubeconfig: -- " $@ " )
151
+ if [ $? -ne 0 ] ; then
152
+ usage
153
+ fi
154
+
155
+ eval set -- " $parsed "
156
+
157
+ NAME=" "
158
+ ORGANIZATION=" portworx"
159
+ PXSECRET=" px-user-token"
160
+ NAMESPACE=" "
161
+ CONTEXT=" "
162
+ OUTDIR=" ."
163
+
164
+ while true ; do
165
+ case " $1 " in
166
+ --organization) ORGANIZATION=" $2 " ; shift 2 ;;
167
+ --namespace) NAMESPACE=" $2 " ; shift 2 ;;
168
+ --name) NAME=" $2 " ; shift 2 ;;
169
+ --px-secret) PXSECRET=" $2 " ; shift 2 ;;
170
+ --outdir) OUTDIR=" $2 " ; shift 2 ;;
171
+ --context) CONTEXT=" $2 " ; shift 2;;
172
+ --kubeconfig) export KUBECONFIG=" $2 " ; shift 2;;
173
+ -h | --help) usage;;
174
+ --) shift ; break ;;
175
+ * ) usage; break ;;
176
+ esac
177
+ done
178
+
179
+ if [ " $NAME " = " " ] ; then
180
+ echo " Must provide a user name"
181
+ exit 1
182
+ fi
183
+
184
+ if [ " $NAMESPACE " = " " ] ; then
185
+ NAMESPACE=" $NAME "
186
+ fi
187
+
188
+ if [ " $CONTEXT " = " " ] ; then
189
+ CONTEXT=$( kubectl config view --raw -o jsonpath=" {.current-context}" )
190
+ fi
191
+
192
+ if [ " $OUTDIR " != " ." -a ! -d " $OUTDIR " ] ; then
193
+ runorfail mkdir $OUTDIR
194
+ fi
195
+
196
+ # Check that kubectl config works
197
+ if ! kubectl --context=$CONTEXT version --short=true > /dev/null 2>&1 ; then
198
+ fail " kubectl failed to communicate with Kubernetes. Is the kubeconfig setup correctly?"
199
+ fi
200
+
201
+ # Use the current context cluster address and CA Cert data
202
+ cafile=/tmp/cacert.$$
203
+ cluster=$( kubectl config view --raw -o jsonpath=" {.contexts[?(@.name==\" $CONTEXT \" )].context.cluster}" )
204
+ address=$( kubectl config view --raw -o jsonpath=" {.clusters[?(@.name==\" $cluster \" )].cluster.server}" )
205
+ cacert_data=$( kubectl config view --raw -o jsonpath=" {.clusters[?(@.name==\" $cluster \" )].cluster.certificate-authority-data}" )
206
+ if [ -z ${cacert_data} ] ; then
207
+ fail " No CA cert data found in cluster ${cluster} "
208
+ elif [ ! -f ${cacert_data} ] ; then
209
+ echo ${cacert_data} | base64 -d > $cafile
210
+ delete_cafile=$cafile
211
+ else
212
+ cafile=$cacert_data
213
+ fi
214
+
215
+ createUserKubeconfig " ${NAME} " " ${OUTDIR} " " ${cafile} "
216
+
217
+ # Cleanup
218
+ if [ -f $delete_cafile ] ; then
219
+ rm -f $delete_cafile > /dev/null 2>&1
220
+ fi
0 commit comments