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;
  ...
  @Override
  public 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);
  }

  @VisibleForTesting
  void 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相关的操作。

1885_1.jpeg

生成token文件

使用hdfs fetchdt test.token可以生成token文件,本质上调用rpc getDelegationToken接口。生成token之前要保证Kerberos已经登录(kinit user)。

1885_2.jpeg

查看token文件

使用hdfs fetchdt --print --verbose test.token可以查看token文件。

1885_3.jpeg

使用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接口。

喜欢就点赞、收藏一下~

未经允许禁止转载~
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇