Kerberos之Beeline客户端参数解析

  在Kerberos认证体系下,Beeline客户端连接HiveServer2的参数一般是这样的:beeline -u “jdbc:hive2://<URL>:10000/default;principal=hive/_HOST@<realm>;hive.server2.proxy.user=<username>”。在初学Kerberos的时候,关于连接参数中的principal始终是百思不得其解,为什么一定要写成principal=hive/_HOST@<realm>这种形式?hive换成其他的可不可以?中间的这个_HOST又是怎么确定的?这个principal到底是用户的principal还是服务的principal?
  这些问题的答案可能对于大部分人来说是显而易见的,然而对于我这只小菜就来说就很容易想不明白。而我对于感兴趣的问题又喜欢一追到底,有点钻牛角尖儿。
  下面我来说一下针对上述问题,自己一些浅显的理解。可能不对,欢迎大家批评指正。

HiveConnection的openTransport()方法解析

  接上文Kyuubi服务源码解析:FrontendService,文末提到了HiveConnection的openTransport()方法,来看一下openTransport()做了什么。

HiveConnection.java:

  • openTransport()方法
  private void openTransport() throws Exception {
    assumeSubject =
        JdbcConnectionParams.AUTH_KERBEROS_AUTH_TYPE_FROM_SUBJECT.equals(sessConfMap
            .get(JdbcConnectionParams.AUTH_KERBEROS_AUTH_TYPE));
    //一般来说是调用createBinaryTransport()方法
    transport = isHttpTransportMode() ? createHttpTransport() : createBinaryTransport();
    if (!transport.isOpen()) {
      transport.open();
    }
    logZkDiscoveryMessage("Connected to " + connParams.getHost() + ":" + connParams.getPort());
  }
  • createBinaryTransport()方法
  /**
   * Create transport per the connection options
   * Supported transport options are:
   *   - SASL based transports over
   *      + Kerberos
   *      + Delegation token
   *      + SSL
   *      + non-SSL
   *   - Raw (non-SASL) socket
   *
   *   Kerberos and Delegation token supports SASL QOP configurations
   * @throws SQLException, TTransportException
   */
  private TTransport createBinaryTransport() throws SQLException, TTransportException {
    try {
      TTransport socketTransport = createUnderlyingTransport();
      // handle secure connection if specified
      if (!JdbcConnectionParams.AUTH_SIMPLE.equals(sessConfMap.get(JdbcConnectionParams.AUTH_TYPE))) {
        // If Kerberos
        Map<String, String> saslProps = new HashMap<String, String>();
        SaslQOP saslQOP = SaslQOP.AUTH;
        if (sessConfMap.containsKey(JdbcConnectionParams.AUTH_QOP)) {
          ***省略部分代码***
        } else {
          // If the client did not specify qop then just negotiate the one supported by server
          saslProps.put(Sasl.QOP, "auth-conf,auth-int,auth");
        }
        saslProps.put(Sasl.SERVER_AUTH, "true");
        //即JDBC连接参数中“principal=hive/_HOST@realms”
        if (sessConfMap.containsKey(JdbcConnectionParams.AUTH_PRINCIPAL)) {
          transport = KerberosSaslHelper.getKerberosTransport(
              //这里的principal获取的是JDBC连接参数中的principal
              sessConfMap.get(JdbcConnectionParams.AUTH_PRINCIPAL), host,
              socketTransport, saslProps, assumeSubject);
        } else {
          // If there's a delegation token available then use token based connection
          String tokenStr = getClientDelegationToken(sessConfMap);
          if (tokenStr != null) {
            transport = KerberosSaslHelper.getTokenTransport(tokenStr,
                host, socketTransport, saslProps);
          } else {
            // we are using PLAIN Sasl connection with user/password
            String userName = getUserName();
            String passwd = getPassword();
            // Overlay the SASL transport on top of the base socket transport (SSL or non-SSL)
            transport = PlainSaslHelper.getPlainTransport(userName, passwd, socketTransport);
          }
        }
      } else {
        // Raw socket connection (non-sasl)
        transport = socketTransport;
      }
    } catch (SaslException e) {
      throw new SQLException("Could not create secure connection to "
          + jdbcUriString + ": " + e.getMessage(), " 08S01", e);
    }
    return transport;
  }

该方法内部调用了KerberosSaslHelper.getKerberosTransport()方法。
KerberosSaslHelper.getKerberosTransport()中的调用关系如下所示:

《Kerberos之Beeline客户端参数解析》 KerberosSaslHelper.getKerberosTransport()方法

createClientTransport()方法定义:

《Kerberos之Beeline客户端参数解析》 createClientTransport方法

  从createClientTransport()方法的注释中,可以看出principalConfig(也就是JDBC连接参数中的“principal=hive/_HOST@realms”)
指的是服务器的principal,就是JDBC客户端请求服务的principal,当然这个服务的principal是在hive-site.xml中已经配置好的(见如下两张图)。那么这里的
_HOST就应为请求的服务所在机器的hostname,因为如果principal中的_HOST对应的机器都没有开启要请求的服务,又怎么访问服务呢?
所以Beeline客户端连接参数中principal的_HOST所指的服务器一定要确认开启了要请求的服务

《Kerberos之Beeline客户端参数解析》 hive-site.xml中metastore服务Kerberos配置

《Kerberos之Beeline客户端参数解析》 hive-site.xml中hiveserver2服务Kerberos配置

  上面两张图中metastore和hiveserver2服务的名字都叫hive,难免有些困惑,这个我后续会调研清楚。

  上面啰嗦了一大堆,可能理解的不对,但初衷还是要讲明白JDBC连接参数中principal的真正含义。这对于在HiveServer2或者Kyuubi业务场景下理解Kerberos认证流程至关重要。

  • HadoopThriftAuthBridge.Client的createClientTransport()方法
    public TTransport createClientTransport(
        String principalConfig, String host,
        String methodStr, String tokenStrForm, final TTransport underlyingTransport,
        final Map<String, String> saslProps) throws IOException {
      final AuthMethod method = AuthMethod.valueOf(AuthMethod.class, methodStr);

      TTransport saslTransport = null;
      switch (method) {
      case DIGEST:
        ***省略部分代码***

      case KERBEROS:
        String serverPrincipal = SecurityUtil.getServerPrincipal(principalConfig, host);
        final String names[] = SaslRpcServer.splitKerberosName(serverPrincipal);
        if (names.length != 3) {
          throw new IOException(
              "Kerberos principal name does NOT have the expected hostname part: "
                  + serverPrincipal);
        }
        try {
          return UserGroupInformation.getCurrentUser().doAs(
              new PrivilegedExceptionAction<TUGIAssumingTransport>() {
                @Override
                public TUGIAssumingTransport run() throws IOException {
                  TTransport saslTransport = new TSaslClientTransport(
                    method.getMechanismName(),
                    null,
                    names[0], names[1],
                    saslProps, null,
                    underlyingTransport);
                  return new TUGIAssumingTransport(saslTransport, UserGroupInformation.getCurrentUser());
                }
              });
        } catch (InterruptedException | SaslException se) {
          throw new IOException("Could not instantiate SASL transport", se);
        }

      default:
        throw new IOException("Unsupported authentication method: " + method);
      }
    }

这段代码中你看到了什么?UGI。对,UGI。

    原文作者:此间少年仍犹在
    原文地址: https://www.jianshu.com/p/79626006351d
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞