HDFSRPC安全认证Token篇2
本文为HDFSRPC安全认证Token的补充。主要阐述Token的结构,Token相关RPC接口以及Token如何使用。
写在前面
请先阅读HDFSRPC安全认证Token篇。
Token简介
Token作为Kerberos的补充,当完成kerberos验证以后,服务主体的可以通过getDelegationToken接口来获取token,后续client端都可以通过Token来访问文件系统。那Token被盗用,非法客户端是否可以访问文件系统?答案是肯定的。因为Token本身就是访问凭证,里面包含了id,password等用于登录验证。
Token的结构
tokenproto的结构其实比较简单。
message TokenProto {required bytes identifier = 1;required bytes password = 2;required string kind = 3;required string service = 4;
}
identifier:tokenid。
password:此token的密码。
kind:token的kind,HDFS为HDFS_DELEGATION_TOKEN。
service:为fs.defaultFs中的host:port
其中比较复杂的identifier,可以发现identifier为bytes,而不是常见的int,UUID等,因为identifier其实多个数据拼接而成的。值得注意的hadoop本身支持自有存储自定义自己TokenIdentifier的,包括如何自己生成identifier的bytes。但是也可以直接实现hadoop的AbstractDelegationTokenIdentifier类,而hdfs就是实现了AbstractDelegationTokenIdentifier类。
AbstractDelegationTokenIdentifier.java
public abstract class AbstractDelegationTokenIdentifier extends TokenIdentifier {private static final byte VERSION = 0;private Text owner;private Text renewer;private Text realUser;private long issueDate;private long maxDate;private int sequenceNumber;private int masterKeyId = 0;...@Overridepublic void readFields(DataInput in) throws IOException {byte version = in.readByte();if (version != VERSION) {throw new IOException("Unknown version of delegation token " + version);}owner.readFields(in, Text.DEFAULT_MAX_LEN);renewer.readFields(in, Text.DEFAULT_MAX_LEN);realUser.readFields(in, Text.DEFAULT_MAX_LEN);issueDate = WritableUtils.readVLong(in);maxDate = WritableUtils.readVLong(in);sequenceNumber = WritableUtils.readVInt(in);masterKeyId = WritableUtils.readVInt(in);}@VisibleForTestingvoid writeImpl(DataOutput out) throws IOException {out.writeByte(VERSION);owner.write(out);renewer.write(out);realUser.write(out);WritableUtils.writeVLong(out, issueDate);WritableUtils.writeVLong(out, maxDate);WritableUtils.writeVInt(out, sequenceNumber);WritableUtils.writeVInt(out, masterKeyId);}...
}
owner:token的所有者,其实就是kerberos的用户。
renewer:token的更新者。
realuser:涉及hadoop的proxyuser,暂无介绍。
issueDate,maxData:创建时间,过期时间。
sequenceNumber:token序列号。
masterKeyId:默认为0,暂无介绍。
值得注意的是read和write方法,里面包含identifier bytes的结构。bytes本质上是由version和各个属性顺序写入组成。
Token的sasl验证
由于id和password都为bytes,sasl会使用base64加密以后再作为sasl的user,password使用。
SaslRpcClient.java
private static class SaslClientCallbackHandler implements CallbackHandler {private final String userName;private final char[] userPassword;public SaslClientCallbackHandler(Token<? extends TokenIdentifier> token) {this.userName = SaslRpcServer.encodeIdentifier(token.getIdentifier());this.userPassword = SaslRpcServer.encodePassword(token.getPassword());}...
}
SaslRpcServer.java
static String encodeIdentifier(byte[] identifier) {return new String(Base64.encodeBase64(identifier), StandardCharsets.UTF_8);}static char[] encodePassword(byte[] password) {return new String(Base64.encodeBase64(password), StandardCharsets.UTF_8).toCharArray();}
验证本质上客户端会发送id和由password生成sign到server,server会根据token id获取password,以相同的算法生成sign,然后比较,如果相同就验证成功,反之则失败。
Token的使用
hdfs fetchdt是专门用于token相关的操作。
生成token文件
使用hdfs fetchdt test.token可以生成token文件,本质上调用rpc getDelegationToken接口。生成token之前要保证Kerberos已经登录(kinit user)。
查看token文件
使用hdfs fetchdt --print --verbose test.token可以查看token文件。
使用token访问文件系统
官网上并没有使用token访问文件系统的教程。根据UserGroupInformation.java源码可以通过设置环境变量HADOOP_TOKEN_FILE_LOCATION来使用token文件访问文件系统。
UserGroupInformation.java
String fileLocation = System.getenv(HADOOP_TOKEN_FILE_LOCATION);if (fileLocation != null) {// Load the token storage file and put all of the tokens into the// user. Don't use the FileSystem API for reading since it has a lock// cycle (HADOOP-9212).File source = new File(fileLocation);LOG.debug("Reading credentials from location set in {}: {}",HADOOP_TOKEN_FILE_LOCATION,source.getCanonicalPath());if (!source.isFile()) {throw new FileNotFoundException("Source file "+ source.getCanonicalPath() + " from "+ HADOOP_TOKEN_FILE_LOCATION+ " not found");}Credentials cred = Credentials.readTokenStorageFile(source, conf);LOG.debug("Loaded {} tokens", cred.numberOfTokens());loginUser.addCredentials(cred);}
使用export HADOOP_TOKEN_FILE_LOCATION=/token_path/test.token来设置。后续使用hdfs dfs命令都会使用token,即使没有kinit,也能访问文件系统。如果token文件无法使用了,可以通过unset HADOOP_TOKEN_FILE_LOCATION来重新使用kerberos访问文件系统,获取新tokenfile等。
token的renew,cancel
hdfs fetchdt --renew test.token命令对应rpc renewDelegationToken接口。
hdfs fetchdt --cancel test.token命令对应rpc cancelDelegationToken接口。
喜欢就点赞、收藏一下~