概述
openshift API的调用机制遵循OAuth 2.0机制,在调用API进行操作前需要先获取access token,然后拿着这个token再去调用相应的API。
open shift中提供了两种形式的token,一个是session token ,一个是service account token.前者有效期24小时,后者长期有效,但是后者是属于某一 namespace,而且能调用的API可能比较局限,本文两种方法都会介绍。
获取token的几种方法
Authorization Code Grant
此方法需要先向/oauth/authorize发送一个请求获取一个Authorization Code,
然后再拿着这个Authorization Code往/oauth/token发送请求获取access token。
这个方法比较麻烦,不建议使用。
Resource Owner Password Credentials Grant
Client Credentials Grant
此方法需要客户端有特别的认证。
Extension Grants
Implicit Grant
这个方法是常用的,如果你想调用openshift API,建议采用此方法
使用Session Token调用API
使用的是Implicit Grant方法
使用curl命令获取session token
curl -u username:password -kv -H "X-CSRF-Token: 1" 'https://example.test.com:8443/oauth/authorize?client_id=openshift-challenging-client&response_type=token'
username是用户名,password是密码
成功返回的信息如下:
..............
HTTP/2 302
..................
location: https://example.test.com:8443/oauth/token/implicit#access_token=asrpT-EhPSEG-0hYPk5v76MzemoxWIc0DurGqk6OnlI&expires_in=86400&scope=user%3Afull&token_type=Bearer
................
成功返回302,这是跳转代码,token就放在header中的location里面,如果curl命令中没有-v参数的话你就看不到token信息,或者你用postman来发送请求也看不到token,返回码是200,这是因为某些user-agent类型的client无法获取跳转之后的信息
在程序中获取session token
由于token是放在返回header中的location里面,所以需要去header去取
在Java程序中可以这样获取token
private static final String AUTHORIZATION = "Authorization";
private static final String LOCATION = "Location";
private static final String AUTHORIZE_PATH = "oauth/authorize?response_type=token&client_id=openshift-challenging-client";
private static final String BEFORE_TOKEN = "access_token=";
private static final String AFTER_TOKEN = "&expires";
private final OkHttpClient client;
private final OpenShiftConfig config;
private String authorize() {
try {
OkHttpClient.Builder builder = client.newBuilder();
builder.interceptors().remove(this);
OkHttpClient clone = builder.build();
String credential = Credentials.basic(config.getUsername(), new String(config.getPassword()));
URL url = new URL(URLUtils.join(config.getMasterUrl(), AUTHORIZE_PATH));
Response response = clone.newCall(new Request.Builder().get().url(url).header(AUTHORIZATION, credential).build()).execute();
response.body().close();
response = response.priorResponse() != null ? response.priorResponse() : response;
response = response.networkResponse() != null ? response.networkResponse() : response;
String token = response.header(LOCATION);
if (token == null || token.isEmpty()) {
throw new KubernetesClientException("Unexpected response (" + response.code() + " " + response.message() + "), to the authorization request. Missing header:[" + LOCATION + "]!");
}
token = token.substring(token.indexOf(BEFORE_TOKEN) + BEFORE_TOKEN.length());
token = token.substring(0, token.indexOf(AFTER_TOKEN));
return token;
} catch (Exception e) {
throw KubernetesClientException.launderThrowable(e);
}
}
由于新获取的token会在24小时后过期,所以你需要在24小时后重新生成新的token
在程序里面有两种做法:
*在调用API的时候判断返回代码如果是401: Unauthorized, 就重新生成token
*创建一个对象每隔24小时重新生成一个token,每次调用API之前只管从这个对象获取token就可以了
使用session token调用API
curl -H "Authorization: Bearer xxxxxxxxxxxxx" -H 'Accept: application/json' -X GET -k https://example.test.com:8443/apis/project.openshift.io/v1/projects/default
使用Serviceaccount Token调用API
我们在default项目中创建一个serviceaccount caller,然后给这个service account赋予集群管理员的权限,这样就可以用它来调用所有的API了,最后用这个service account的token调用一个API测试是否成功。
切换到default项目
oc project default
创建serviceaccount caller
oc create serviceaccount caller
给这个service account赋予集群管理员的权限
oc policy add-cluster-role-to-user cluster-admin -z caller
获取token
oc serviceaccounts get-token caller
用刚刚获得的token来调用一个API试试
curl -H "Authorization: Bearer xxxxxxxxxxxxx" -H 'Accept: application/json' -X GET -k https://example.test.com:8443/apis/project.openshift.io/v1/projects/default
上面是用oc命令行来获取serviceaccount token的,那如果要调API怎么来获取serviceaccount token呢?
我们可以用oc命令加上–loglevel=10来获取详细的调用API
oc serviceaccounts get-token ops --loglevel=10
可以看到总共发出了两条curl命令
第一条curl
curl -kv -XGET -H "Accept: application/json" -H "Authorization: Bearer xxxxxxxxx" https://example.test.com:8443/api/v1/namespaces/default/serviceaccounts/ops
用来获取ops的secret名称, 请求返回结果如下:
{"kind":"ServiceAccount","apiVersion":"v1","metadata":{"name":"ops","namespace":"default","selfLink":"/api/v1/namespaces/default/serviceaccounts/ops","uid":"3e3c5e60-e1a5-11e8-8d64-525400d56e6b","resourceVersion":"36316915","creationTimestamp":"2018-11-06T09:20:46Z"},"secrets":[{"name":"ops-token-6pn9s"},{"name":"ops-dockercfg-2wlx4"}],"imagePullSecrets":[{"name":"ops-dockercfg-2wlx4"}]}
第二条curl
curl -kv -XGET -H "Accept: application/json" -H "Authorization: Bearer xxxxxxxxx" https://example.test.com:8443/api/v1/namespaces/default/secrets/ops-token-6pn9s
获得token,但是注意要把结果反加密
{
"kind": "Secret",
"apiVersion": "v1",
"metadata": {
........
}
},
"data": {
"ca.crt": "..........",
"namespace": "ZGVmYXVsdA==",
"service-ca.crt": "............",
"token": "ZXlKaGJHY........RWTWFZeGg2LVhoR1E="
},
"type": "kubernetes.io/service-account-token"
反加密token, 获得的token才是真正的token
echo "ZXlKaGJHY........RWTWFZeGg2LVhoR1E=" | base64 --decode