目录

  • 1 需求
  • 2 Hive 权限的通常做法
  • 3 LDAP
  • 3.1 简介
  • 3.2 OpenLDAP
  • 3.3 OpenLDAP 的优点
  • 3.4 LDAP 中的名词解释
  • 3.5 关于卸载
  • 3.6 安装
  • 3.6.1 方式一:yum 方式
  • 3.6.2 方式二:rpm 方式安装
  • 3.6.3 安装中出现的问题解决
  • 3.6.4 OpenLDAP 配置(通过配置方式)
  • 3.6.5 创建用户
  • 3.6.6 对用户的操作
  • 3.6.6.1 OpenLDAP 管理命令汇总
  • 3.6.6.2 ldapsearch,搜索目录树条目
  • 3.6.6.3 ldapadd,使用 LDIF 格式添加目录树条目
  • 3.6.6.4 ldapdelete,删除 目录树条目
  • 3.6.6.5 ldapmodify,修改目录树条目
  • 3.6.6.6 ldapwhoami,验证服务器身份
  • 3.6.6.7 ldapmodrdn,修改目录树 DN 条目
  • 3.6.6.8 ldapcompare,判断 DN 值和指定参数值是否属于同一个条目
  • 3.6.6.9 ldappasswd,修改密码
  • 3.6.6.10 slaptest, 验证 slapd.conf 文件
  • 3.6.6.11 slapindex, 创建 OpenLDAP 目录树索引
  • 3.6.6.12 slapcat, 数据条目转为 LDIF 文件
  • 4 CDH
  • 4.1 Hive开启 LDAP
  • 4.2 Impala开启 LDAP
  • 4.3 Hue开启 LDAP
  • 5 使用
  • 5.1 Hue
  • 5.2 Beeline
  • 5.3 impala-shell
  • 5.4 关于 impala-shell执行脚本的问题
  • 5.5 JDBC 方式查询带 LDAP 的Hive 数据
  • 5.6 JDBC 方式查询带 LDAP 认证的Impala数据
  • 5.7 Spring Boot访问 LDAP 认证的Impala数据


1 需求

大数据集群中会运行有多个服务,这些服务在不添加权限与认证时,只要网络是通的,理论上就可以正常调用到服务,这是就面对一个问题,因为网络并不总是安全的,在开放的环境下难免会有不合法的请求访问,甚至会遭受到恶意的攻击。因此企业的生产环境一般会通过跳板机或堡垒机,来隔离生产环境,这样只有成功登陆跳板机或堡垒机的用户才能访问给定的服务器环境。

但是比如在一个集群中,该用户可以访问这个节点的某个服务,但是限制这个用户访问另外的服务,比如这个用户在 node1 节点上可以访问MySQL,但是不能访问 Impala 中的数据,这个就需要对服务添加用户认证。

对于这个需求,虽然使用 Kerberos 也能解决,但是这里我们可以不用判断访问的用户是否合法(假设通过堡垒机进入的用户都是合法的),只需要对请求的服务进行用户认证,通过就可以调用服务,因此这里我们选择使用 LDAP。

本次需求主要对 CDH 环境中的 Hive、Impala、Hue 添加 LDAP 用户认证。



2 Hive 权限的通常做法

通过查看源码,hive-service中的认证部分留有接口,也有一个实现类CustomAuthenticationProviderImpl,但是查看这个实现类的源码,发现对于认证的方法Authenticate 的实现并为做认证,而是调用了未实现的接口的方法,因此使用这种方式,需要用户继承PasswdAuthenticationProvider 接口类,重写实现其认证方法。

LDAP认证RADIUS认证 ldap认证方式_CDH


LDAP认证RADIUS认证 ldap认证方式_LDAP_02


自定义重写后的代码如下,重点部分是重写Authenticate 方法。

package yore;

import javax.security.sasl.AuthenticationException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hive.conf.HiveConf;
import org.slf4j.Logger;

public class CustomPasswdAuthenticator implements org.apache.hive.service.auth.PasswdAuthenticationProvider {
    private Logger LOG = org.slf4j.LoggerFactory.getLogger(CustomPasswdAuthenticator.class);
    private static final String HIVE_JDBC_PASSWD_AUTH_PREFIX="hive.jdbc_passwd.auth.%s";
    private Configuration conf=null;

    @Override
    public void Authenticate(String userName, String passwd) throws AuthenticationException {
        LOG.info("user: "+userName+" try login.");
        String passwdConf = getConf().get(String.format(HIVE_JDBC_PASSWD_AUTH_PREFIX, userName));
        if(passwdConf==null){
            String message = "user's ACL configration is not found. user:"+userName;
            LOG.info(message);
            throw new AuthenticationException(message);
        }
        if(!passwd.equals(passwdConf)){
            String message = "user name and password is mismatch. user:"+userName;
            throw new AuthenticationException(message);
        }
    }

    public Configuration getConf() {
        if(conf==null){
            this.conf=new Configuration(new HiveConf());
        }
        return conf;
    }
    public void setConf(Configuration conf) {
        this.conf=conf;
    }
}

将编译好的jar包,放置到各个Hive 的 lib目录下,如果是 CDH 就放到这个目录下 /opt/cloudera/parcels/CDH/lib/hive/lib

打开CDH 管理页面,依次点击 Hive -> 配置 -> 搜索hive-site,添加下面配置项,如果配置多个用户和密码,可以添加配置多个项hive.jdbc_passwd.auth.reportmart即可:

<property>
<name>hive.security.authorization.enabled</name>
    <value>true</value>
    <description>enableor disable the hive clientauthorization</description>
</property>

<property>
    <name>hive.security.authorization.createtable.owner.grants</name>
    <value>ALL</value>
    <description>theprivileges automatically granted to the ownerwhenever a table gets created. Anexample like "select,drop" willgrant select and drop privilege to theowner of the table</description>
</property>

<!--指定解析jar包-->
<property>
    <name>hive.server2.custom.authentication.class</name>
    <value>yore.CustomPasswdAuthenticator</value>
</property>
<property>
    <name>hive.server2.authentication</name>
    <value>CUSTOM</value>
    <description>
      Expects one of [nosasl, none, ldap, kerberos, pam, custom].
      Client authentication types.
        NONE: no authentication check
        LDAP: LDAP/AD based authentication
        KERBEROS: Kerberos/GSSAPI authentication
        CUSTOM: Custom authentication provider
                (Use with property hive.server2.custom.authentication.class)
        PAM: Pluggable authentication module
        NOSASL:  Raw transport
    </description>
  </property>
<property>
    <name>hive.jdbc_passwd.auth.hiveuser01</name>
    <value>abc123</value>
    <description>配置的用户名为:hiveuser01,密码为:abc123。如果要配置多个账户和密码,添加多个</description>
</property>

LDAP认证RADIUS认证 ldap认证方式_Hive_03

配置完毕后,重启过时的服务。使用Beeline连接进行测试:

# 用户名或者密码错误时
# 会报如下的错误
#  Error: Could not open client transport with JDBC Uri: jdbc:hive2://cdh3:10000/default: Peer indicated failure: Error validating the login (state=08S01,code=0)
beeline --color=true -d "org.apache.hive.jdbc.HiveDriver" -u "jdbc:hive2://cdh3:10000/default" -n hiveuser01 -p 123456

# 输入正确的用户名和密码
beeline --color=true -d "org.apache.hive.jdbc.HiveDriver" -u "jdbc:hive2://cdh3:10000/default" -n hiveuser01 -p abc123

# 用户名或者密码错误时
beeline --color=true -d "org.apache.hive.jdbc.HiveDriver" -u "jdbc:hive2://cdh3:10000/default" -n hive -p hive123

在连接的过程中可能会出现如下的错误

Error: Could not open client transport with JDBC Uri: jdbc:hive2://cdh3:10000/default: Failed to open new session: java.lang.IllegalArgumentException: Cannot modify hive.query.redaction.rules at runtime. It is not in list of params that are allowed to be modified at runtime (state=08S01,code=0)

我们可以直接排查,执行在hive server2节点如下

# 环境中查找 ive.query.redaction.rules 配置项
cd /etc/hive
grep -rni "hive.query.redaction.rules"
conf.cloudera.hive/hive-env.sh:7:export HIVE_OPTS="${HIVE_OPTS} --hiveconf hive.query.redaction.rules=${HIVE_CONF_DIR}/redaction-rules.json --hiveconf hive.exec.query.redactor.hooks=org.cloudera.hadoop.hive.ql.hooks.QueryRedactor"

# 去掉hive.query.redaction.rules参数
# 从上面可以看到在配置文件中 hive-env.sh 中第7行加载了这个配置项,我们直接去掉这个校验
vim /etc/hive/conf.cloudera.hive/hive-env.sh
# 大概在第7行,

# 如果还是提示 Cannot modify hive.query.redaction.rules at runtime ,这个是环境中匹配的验证规则没有及时改变,
# 但是这个并不影响正常的服务调用,如果想在环境中使用 beeline 工具访问,
# 可以重新现在一个Beeline(比如 Spark 包)

这种方式适合单独部署 Hive 的情况下,如果又集成了 Hue,那可能会造成 Hue 无法访问Hive 数据,如果是在 CDH 环境,既要对 Hive 添加用户认证,又要对 Impala 添加认证,为了统一管理,有必要使用 LDAP 统一管理,这个在上面的 hive-site.xml 也能看到,hive 是支持 LDAP 认证方式。



3 LDAP

3.1 简介

LDAP是一款轻量级目录访问协议(Lightweight Directory Access Protocol,简称LDAP)。OpenLDAP属于开源集中账号管理架构的实现,且支持众多系统版本,被广大互联网公司所采用。

LDAP在TCP/IP之上定义了一个相对简单的升级和搜索目录的协议。LDAP具有两个标准,分别是 X.500 和 LDAP。OpenLDAP 是基于 X.500 标准的,而且去除了 X.500 复杂的功能并且可以根据自我需求定制额外扩展功能,但与 X.500 也有不同之处,例如OpenLDAP支持TCP/IP协议等,目前TCP/IP是Internet上访问互联网的协议。

3.2 OpenLDAP

OpenLDAP是直接运行在更简单和更通用的 TPC/IP 或其他可靠的传输协议层上,避免了在 OSI 会话层(Open System Interconnection)和表示层的开销,使连接的建立和包的处理更简单、更快,对于互联网和企业网应用更理想。LDAP 提供并实现目录服务的信息服务。目录服务是一种特殊的数据库系统,对于数据的读取、浏览、搜索有很好的效果。目录服务一般用来包含基于属性的描述信息并支持精细复杂的过滤功能,但 OpenLDAP 目录服务不支持通用数据库的大量更新操作所需要的复杂事物管理或回滚策略等。

OpenLDAP 默认以 Berkeley DB 作为后端数据库,Berkeley DB 数据库主要以散列的数据类型进行存储,如以键值对的方式进行存储。Berkeley DB是一类特殊的数据库,主要用于搜索、浏览、更新查询操作,一般对于一次写入数据多次查询或搜索有很好的效果。Berkeley DB 数据库时面向查询进行优化、面向读取进行优化的数据库。Berkeley DB 不支持事务性数据库(MySQL、MariaDB、Oracle等)所支持的高并发的高吞吐量以及复杂的事物操作。

OpenLDAP 目录中的信息时按照树型结构进行组织的,具体信息存储在条目(entry)中,条目可以看成关系数据库中的表记录,条目是具有专有名(Distinguished Name,DN)的属性,DN 是用来引用条目,DN 相当于关系数据库中的主键,是唯一的。属性有类型(type)和一个或者多个值(value)组成,相当于关系数据库中字段的概念。

3.3 OpenLDAP 的优点

  • OpenLDAP 是一个跨平台的标准互联网协议,它基于 X.500 标准协议
  • OpenLDAP 提供静态数据查询搜索,不需要像在关系数据库中那样通过 SQL 语句维护数据库信息。
  • OpenLDAP 基于推和拉的机制实现节点间的数据同步,简称复制(replication)并提供基于 TLS、SASL 的安全认证机制,实现数据加密传输以及 Kerberos 密码验证功能。
  • OpenLDAP 可以基于第三方开源软件实现负载(LVS、HAProxy)以及高可用性姐姐方案,24小时提供验证服务,比如 Headbeat、Corosync、Keepalived等。
  • OpenLDAP 数据元素使用简单的文本字符串(简称 LDIF 文件)而非一些特殊字符,便于维护管理目录树条目。
  • OpenLDAP 可以实现用户的几种认证管理,所有关于账号的变更,只需要在 OpenLDAP 服务端直接操作,无需到每台客户端进行操作,影响范围为全局。
  • OpenLDAP 默认使用协议简单,比如支持 TCP/IP 协议传输条目数据,通过使用查找操作实现对目录信息的读写操作,童昂可以通过加密的方式进行获取目录条目信息。
  • OpenLDAP 产品应用于各大应用平台(Nginx、HTTP、vsftpd、Samba、SVN、Postfix、OpenStack、Hadoop等)、服务器(HP、IBM、Dell等)以及存储(EMC、NetApp等)控制台,负责管理账号验证功能,实现账号统一管理。
  • OpenLDAP 实现具有费用低、配置简单、功能强大、管理容易以及开源的特点
  • OpenLDAP 通过 ACL(Access Control List)灵活控制用户访问数据的权限,从而保证数据的安全性。

3.4 LDAP 中的名词解释

名词或缩写

全称

描述

Entry

条目,也叫记录项,是LDAP中最基本的颗粒,就像字典中的词条,或者是数据库中的记录。通常对LDAP的添加、删除、更改、检索都是以条目为基本对象的。

Attribute

每个条目都可以有很多属性(Attribute),比如常见的人都有姓名、地址、电话等属性。每个属性都有名称及对应的值,属性值可以有单个、多个,比如你有多个邮箱。属性不是随便定义的,需要符合一定的规则,而这个规则可以通过schema制定。

objectClass

 

内置属性。对象类是属性的集合,LDAP预想了很多人员组织机构中常见的对象,并将其封装成对象类。比如人员(person)含有姓(sn)、名(cn)、电话(telephoneNumber)、密码(userPassword)等属性,单位职工(organizationalPerson)是人员(person)的继承类,除了上述属性之外还含有职务(title)、邮政编码(postalCode)、通信地址(postalAddress)等属性。

Schema

 

对象类(ObjectClass)、属性类型(AttributeType)、语法(Syntax)分别约定了条目、属性、值,他们之间的关系如下图所示。所以这些构成了模式(Schema)——对象类的集合。条目数据在导入时通常需要接受模式检查,它确保了目录中所有的条目数据结构都是一致的。

backend & database

 

ldap 的后台进程slapd接收、响应请求,但实际存储数据、获取数据的操作是由Backends做的,而数据是存放在database中,所以你可以看到往往你可以看到backend和database指令是一样的值如 bdb 。一个 backend 可以有多个 database instance,但每个 database 的 suffix 和 rootdn 不一样。openldap 2.4版本的模块是动态加载的,所以在使用backend时需要moduleload back_bdb指令。

telephoneNumber

 

电话号码

TLS

Transport Layer Security

分布式LDAP 是以明文的格式通过网络来发送信息的,包括client访问ldap的密码(当然一般密码已然是二进制的),SSL/TLS 的加密协议就是来保证数据传送的保密性和完整性。

SASL

Simple Authenticaion and Security Layer

SASL 简单身份验证安全框架,它能够实现openldap客户端到服务端的用户验证,也是ldapsearch、ldapmodify这些标准客户端工具默认尝试与LDAP服务端认证用户的方式(前提是已经安装好 Cyrus SASL)。SASL有几大工业实现标准:Kerveros V5、DIGEST-MD5、EXTERNAL、PLAIN、LOGIN。

LDIF

LDAP Data Interchange Format

LDIF(数据交换格式)是LDAP数据库信息的一种文本格式,用于数据的导入导出,每行都是“属性: 值”对。

dn

Distinguished Name

专有名,类似于Linux文件系统中的绝对路径,类似于关系型数据库的主键

Base DN

Base DN

LDAP目录树的最顶部就是根,也就是所谓的“Base DN”,如”dc=mydomain,dc=org”。

rdn

Relative dn

相对专有名,类似于文件系统中的相对路径,它是与目录树结构无关的部分,一般指dn逗号最左边的部分。

dc

Domain Componet

域名组件。将完整域名划分成几个部分,比如域名为 example.org,拆分为 dc=example,dc=org

uid

User Id

用户 ID

cn

Common Name

公共名称,如 Manager

sn

Surname


ou

Organization Unit

组织单位,类似于Linux文件系统中的子目录,它是一个容器对象,组织单位可以包含其他各种对象(包括其他组织单元)

o

Organization

组织名

c

Country

国家

3.5 关于卸载

如果需要重新安装,或者不再使用 LDAP,可以执行如下命令进行卸载。卸载前最好备份一下 /etc/openldap/cert 的文件,否则在最新版本重新安装时可能会缺失此文件,导致LDAP守护进程服务启动报错。同时卸载时需要注意,千万不要卸载openldap-2.4.xx这个包,这个包中的库和 SSH 有共用,如果卸载后会导致 sshd 服务异常,进而通过 ssh 访问会失败。

# 1 查看安装的 openldap
rpm -qa | grep openldap

# 2 关闭服务
systemctl stop slapd
systemctl disable slapd

# 3 卸载服务
yum -y remove openldap-servers openldap-clients

# 4 删除相关目录的数据。/etc/openldap 如果删除 certs 也会删除,安装的时候需要注意。
rm -rf /var/lib/ldap
rm -rf /etc/openldap

# 5 删除ldap用户。
# 可以通过 cat /etc/passwd | grep ldap ,命令查看到系统中存在 ldap 用户
userdel ldap

# 6 查看服务状态
systemctl status slapd

3.6 安装

3.6.1 方式一:yum 方式

如果通过这种方式安装,当可以联网,直接通过 yum 安装即可;如果不能联网,需要配置自己内网的yum源;配置 yum 源 vim /etc/yum.repos.d/difine.repo,主要配置如下内容:

# [] 中是yum 仓库的名称,用于区别不同 yum 仓库及功能
[repo_name]
# 仓库的表述信息
name=
# 跟仓库的路径
baseurl=
# 后面跟数字,表示是否启用该仓库,0表示禁用,1表示启用
enabled=1
# 后面跟数字,表示是否检查软件包的 md5sum,用于校验软件包的安全性。0表示不检查,1表示检查
gpgcheck=1
# 后面跟 path,是一个软件包所使用的签名,一般启用 gpgcheck 时才配置。
gpgkey=

配置完yum 源之后,可以执行如下命令安装

# 1 安装
# 其它节点不用安装 openldap-servers
yum -y install openldap openldap-servers openldap-clients openldap-devel compat-openldap
# 如果需要数据迁移,可以安装 migrationtools
yum install -y migrationtools

# 初始化 OpenLDAP 配置
cp /usr/share/openldap-servers/DB_CONFIG.example /var/lib/ldap/DB_CONFIG
cp /usr/share/openldap-servers/slapd.ldif /etc/openldap/slapd.ldif
chown ldap:ldap /var/lib/ldap/DB_CONFIG
chown -R ldap:ldap /etc/openldap/
chown -R ldap:ldap /var/lib/ldap

3.6.2 方式二:rpm 方式安装

这种方式直接在有网络的地方将安装包下载好,上传到服务上直接安装即可。

# 1 下载
# 在 Cloudera Manager Server服务器上安装额外的包
# 如果安装中报: 
# error: Failed dependencies:
#         libltdl.so.7()(64bit) is needed by openldap-servers-2.4.44-21.el7_6.x86_64
# 需要下载安装 libtool-ltdl
# wget http://mirror.centos.org/centos/7/os/x86_64/Packages/libtool-ltdl-2.4.2-22.el7_3.x86_64.rpm
# rpm -ivh libtool-ltdl-2.4.2-22.el7_3.x86_64.rpm
# rpm -Uvh openldap-2.4.44-21.el7_6.x86_64.rpm
# 
# 同时如果遇到其它依赖缺失,自行到 https://pkgs.org/download 搜索下载,然后安装即可
# openldap-devel-2.4.44-21.el7_6.x86_64.rpm
# compat-openldap-2.3.43-5.el7.x86_64.rpm
# libtool-ltdl-2.4.2-22.el7_3.x86_64.rpm
# cyrus-sasl-devel-2.1.26-23.el7.x86_64.rpm
# cyrus-sasl-2.1.26-23.el7.x86_64.rpm
wget http://mirror.centos.org/centos/7/os/x86_64/Packages/openldap-servers-2.4.44-21.el7_6.x86_64.rpm
wget http://mirror.centos.org/centos/7/os/x86_64/Packages/openldap-clients-2.4.44-21.el7_6.x86_64.rpm
rpm -ivh openldap-servers-2.4.44-21.el7_6.x86_64.rpm openldap-clients-2.4.44-21.el7_6.x86_64.rpm


# 2 查看安装的 openldap
# rpm -e --nodeps 
rpm -qa | grep openldap
# 为了防止环境的影响,对yum 执行如下命令,清除缓存并更新
yum clean all 
yum -y upgrade

# 3 拷贝数据库配置文件,并修改文件的属组为 ldap
cp /usr/share/openldap-servers/DB_CONFIG.example /var/lib/ldap/DB_CONFIG
cp /usr/share/openldap-servers/slapd.ldif /etc/openldap/slapd.ldif
chown ldap:ldap /var/lib/ldap/DB_CONFIG
chown -R ldap:ldap /etc/openldap/
chown -R ldap:ldap /var/lib/ldap

# 4 启动和查看状态
#  有错误时可以查看  journalctl -xe
systemctl start slapd
systemctl enable slapd

# 5 查看日志和状态
systemctl status slapd
journalctl -xe
# 查看 389 端口
netstat -ntplu | grep -i :389
lsof -i:389
  • OpenLDAP 中涉及的路径和文件的说明:
  • /etc/openldap/slapd.ldif,OpenLDAP的主配置文件,记录根域名称、管理员名称、密码、日志、权限等香瓜信息
  • /var/lib/ldap/*,OpenLDAP数据文件存储位置,可以根据需求进行调整。但为了保证数据的安全,一般会推荐放到存储设备上或者独立的分区上。
  • /etc/openldap/slapd.d/*
  • /usr/share/openldap-servers/slapd.ldif ,模板配置文件
  • /usr/share/openldap-servers/DB_CONFIG.example,模板数据库配置文件 schema 录几个
  • /etc/openldap/schema , OpenLDAP Schema 规范存放位置


  • OpenLDAP 监听的端口有以下两个
  • 默认监听端口:389(明文数据传输)
  • 加密监听端口:636(密文数据传输)

3.6.3 安装中出现的问题解决

如果是卸载了openldap-serversopenldap-clients的环境重新安装,可能再次安装后,在没有 /etc/openldap/certs,这回造成在启动 systemctl start slapd时报如下错误:

…… slapd[20259]: main: TLS init def ctx failed: -1
…… slapd[20259]: slapd stopped.
…… slapd[20259]: connections_destroy: nothing to destroy.
…… systemd[1]: slapd.service: control process exited, code=exited status=1
…… systemd[1]: Failed to start OpenLDAP Server Daemon.
…… systemd[1]: Unit slapd.service entered failed state.
…… systemd[1]: slapd.service failed.

如果我们从其它地方拷贝进/etc/openldap/certs/* 或者卸载时旧的残留文件,又会报如下的错误:

…… slapd[28152]: tlsmc_get_pin: INFO: Please note the extracted key file will not be protected with a PIN any more, however it will be still protected at least by file permissions.

关于上面的错误,是新版本(例如 2.4.44 )安装时会出现的一个问题,关于这个问题可以查看这个 Issues 5493 来解决。这样会重新生成新的 /etc/openldap/certs

rm -rf /etc/openldap/
yum reinstall openldap-servers openldap --enablerepo=base,updates

# 下面是一行命令
yum reinstall http://packages.nethserver.org/nethserver/7.7.1908/updates/x86_64/Packages/nethserver-directory-3.3.3-1.ns7.noarch.rpm --enablerepo=base,updates

但是新问题又出现了,重启 slapd 服务,又报了如下的错误:

## systemctl status slapd.service
…… slapd[27348]: daemon: bind(8) failed errno=98 (Address already in use)
…… slapd[27348]: daemon: bind(8) failed errno=98 (Address already in use)
…… systemd[1]: slapd.service: control process exited, code=exited status=1
…… systemd[1]: Failed to start OpenLDAP Server Daemon.
…… systemd[1]: Unit slapd.service entered failed state.
…… systemd[1]: slapd.service failed.

##  journalctl -xe 查看的如下的错误
* slapd[27348]: daemon: bind(8) failed errno=98 (Address already in use)
* slapd[27348]: daemon: bind(8) failed errno=98 (Address already in use)
* slapd[27348]: slapd stopped.
* slapd[27348]: connections_destroy: nothing to destroy.
* systemd[1]: slapd.service: control process exited, code=exited status=1
* systemd[1]: Failed to start OpenLDAP Server Daemon.
-- Subject: Unit slapd.service has failed
-- Defined-By: systemd
-- Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
--
-- Unit slapd.service has failed.
--
-- The result is failed.
* systemd[1]: Unit slapd.service entered failed state.
* systemd[1]: slapd.service failed.

此时我们先查看ldap服务端口是否启来lsof -i:389,如果有先杀掉进程,然后删除掉rm -rf /etc/openldap/certs/password,这样文件发生改动,再次重启 slapd,会重新生成/var/lib/ldap/*,但是会报如下错误,这个问题好解决,直接修改 /var/lib/ldap/ 下的属组 chown ldap:ldap /var/lib/ldap/*

…… runuser[31462]: pam_unix(runuser:session): session closed for user ldap
…… runuser[31464]: pam_unix(runuser:session): session opened for user ldap by (uid=0)
…… runuser[31464]: pam_unix(runuser:session): session closed for user ldap
…… check-config.sh[31439]: Read/write permissions for DB file '/var/lib/ldap/__db.002' are required.
…… runuser[31466]: pam_unix(runuser:session): session opened for user ldap by (uid=0)
…… runuser[31466]: pam_unix(runuser:session): session closed for user ldap
…… systemd[1]: slapd.service: control process exited, code=exited status=1
…… systemd[1]: Failed to start OpenLDAP Server Daemon.
…… systemd[1]: Unit slapd.service entered failed state.
…… systemd[1]: slapd.service failed.

重新启动服务,发现错误发生了改变,显示如下错误信息,根据提示我们查看 /var/run/openldap/slapd.args 的信息,发现属组为 root,因此我们修改这个文件的属组 chown ldap:ldap /var/run/openldap/slapd.args ,再次重启 slapd 服务。

## journalctl -xe 查看的如下的错误
…… slapd[966]: unable to open args file "/var/run/openldap/slapd.args": 13 (Permission denied)
…… slapd[966]: slapd stopped.
…… slapd[966]: connections_destroy: nothing to destroy.
…… systemd[1]: slapd.service: control process exited, code=exited status=1
…… systemd[1]: Failed to start OpenLDAP Server Daemon.
-- Subject: Unit slapd.service has failed
-- Defined-By: systemd
-- Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
--
-- Unit slapd.service has failed.
--
-- The result is failed.
…… systemd[1]: Unit slapd.service entered failed state.
…… systemd[1]: slapd.service failed.

再次重启 slapd 服务,这次服务可以正常启动:

[root@cdh1 openldap]#  systemctl start slapd
[root@cdh1 openldap]#  systemctl status slapd
● slapd.service - OpenLDAP Server Daemon
   Loaded: loaded (/usr/lib/systemd/system/slapd.service; enabled; vendor preset: disabled)
   Active: active (running) since Sun 2020-03-28 10:23:56 CST; 7s ago
     Docs: man:slapd
           man:slapd-config
           man:slapd-hdb
           man:slapd-mdb
           file:///usr/share/doc/openldap-servers/guide.html
  Process: 1295 ExecStart=/usr/sbin/slapd -u ldap -h ${SLAPD_URLS} $SLAPD_OPTIONS (code=exited, status=0/SUCCESS)
  Process: 1266 ExecStartPre=/usr/libexec/openldap/check-config.sh (code=exited, status=0/SUCCESS)
 Main PID: 1305 (slapd)
   CGroup: /system.slice/slapd.service
           └─1305 /usr/sbin/slapd -u ldap -h ldapi:/// ldap:///
Mar 28 10:23:55 cdh1.yore.com runuser[1288]: pam_unix(runuser:session): session opened for user ldap by (uid=0)
Mar 28 10:23:55 cdh1.yore.com runuser[1288]: pam_unix(runuser:session): session closed for user ldap
Mar 28 10:23:55 cdh1.yore.com runuser[1290]: pam_unix(runuser:session): session opened for user ldap by (uid=0)
Mar 28 10:23:55 cdh1.yore.com runuser[1290]: pam_unix(runuser:session): session closed for user ldap
Mar 28 10:23:55 cdh1.yore.com runuser[1292]: pam_unix(runuser:session): session opened for user ldap by (uid=0)
Mar 28 10:23:55 cdh1.yore.com runuser[1292]: pam_unix(runuser:session): session closed for user ldap
Mar 28 10:23:55 cdh1.yore.com slapd[1295]: @(#) $OpenLDAP: slapd 2.4.44 (Jan 29 2019 17:42:45) $
                                                   mockbuild@x86-01.bsys.centos.org:/builddir/build/BUILD/openldap-2.4.44/openldap-2.4.44/servers/slapd
Mar 28 10:23:55 cdh1.yore.com slapd[1305]: hdb_db_open: database "dc=my-domain,dc=com": unclean shutdown detected; attempting recovery.
Mar 28 10:23:56 cdh1.yore.com slapd[1305]: slapd starting
Mar 28 10:23:56 cdh1.yore.com systemd[1]: Started OpenLDAP Server Daemon.

3.6.4 OpenLDAP 配置(通过配置方式)

在 OpenLDAP 2.4 版本后,配置 OpenLDAP 有两种方式,第一种是通过修改配置,另一种通过修改数据库的形式完成配置。

通过配置数据库完成的各种配置,属于动态配置且不需要重启 slapd 进程服务。此配置数据库(cn=config)包含一个基于文本的集合 LDIF 文件(位于/etc/openldap/slapd.d目录下)。

但是也可以使用传统的配置文件(slapd.ldif)方式进行配置,通过配置文件来实现 slapd 的配置方式。slapd.ldif 可以通过编辑器进行配置,但cn=config不建议直接编辑修改,而是采用 ldap 命令进行修改。

/etc/openldap/slapd.ldif配置文件部分配置项说明:

# OpenLDAP 通过加密数据传输加载的配置文件时默认 OpenLDAP 服务采用明文传输数据。
# 在网路数据上传输机器不安全,所以需要通过如下配置将数据加密传输,前提是需要第三方合法的证书机构颁发的数字证书
# TLS settings
#
olcTLSCACertificatePath: /etc/openldap/certs
olcTLSCertificateFile: "OpenLDAP Server"
olcTLSCertificateKeyFile: /etc/openldap/certs/password


# 加载模块
## 对 系统不同位数的支持
olcModulepath:	/usr/lib/openldap
olcModulepath:	/usr/lib64/openldap
## 实现同步
olcModuleload: syncprov.la


# OpenLDAP 服务包含的 schema 文件。后面可以用命令添加
include: file:///etc/openldap/schema/core.ldif


# 指定 OpenLDAP 管理员信息。OpenLDAP 服务管理员对目录树进行管理,如插入、更新、修改及删除等管理操作,要求系统管理员具有 root 身份权限,此管理员用户可以自我修改。
#rootdn  "cn=root,dc=yore,dc=com"

# 指定 OpenLDAP 服务管理员密码
# 明文方式,不建议
#root   yore@123
#rootpw  {SSHA}s2hLnvbtj2MmZtMSqp3PgEQwZMr/082K


# rootdn can always read and write EVERYTHING!
#
# 指定 OpenLDAP 管理员信息。OpenLDAP 服务管理员对目录树进行管理,如插入、更新、修改及删除等管理操作,要求系统管理员具有 root 身份权限,此管理员用户可以自我修改。
#rootdn  "cn=root,dc=yore,dc=com"

# 指定 OpenLDAP 服务管理员密码
# 明文方式,不建议
#root   yore@123
#rootpw  {SSHA}s2hLnvbtj2MmZtMSqp3PgEQwZMr/082K


#
# Server status monitoring
#

dn: olcDatabase=monitor,cn=config
objectClass: olcDatabaseConfig
olcDatabase: monitor
olcAccess: to * by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=external,c
 n=auth" read by dn.base="cn=root,dc=yore,dc=com" read by * none


#
# Backend database definitions
#

dn: olcDatabase=hdb,cn=config
objectClass: olcDatabaseConfig
objectClass: olcHdbConfig
olcDatabase: hdb
olcSuffix: dc=yore,dc=com
olcRootDN: cn=root,dc=yore,dc=com
olcDbDirectory:	/var/lib/ldap
olcDbIndex: objectClass eq,pres
olcDbIndex: ou,cn,mail,surname,givenname eq,pres,sub
# 导入配置数据库。因为版本问题,上面的有些配置项并不一定能全部生效
slapadd -n 0 -F /etc/openldap/slapd.d -l /etc/openldap/slapd.ldif

# 修改 管理员用户


# 重启服务
systemctl  restart slapd

# 从上面的配置我们已经看到,默认已经将 core.schema 导入。
# 我们还可以继续将其他 基础Schema导入(可选)
ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/cosine.ldif
ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/nis.ldif
ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/inetorgperson.ldif

# 检查搜索域。主要查看是否修改成自己配置的域信息
#  -x 信息排序
#  -b 指定搜索范围起点
ldapsearch -x -b "dc=yore,dc=com"
ldapsearch -x -b '' -s base '(objectclass=*)' namingContexts

设置 管理员用户。可以先查看一下数据库中是否有我们设置的管理员的账户信息,如果不存在,我们就需要先设置管理员的账户。

# 查看管理员用户信息
ldapsearch -H ldapi:// -LLL -Q -Y EXTERNAL -b "cn=config" "(olcRootDN=*)" dn olcRootDN olcRootPW

# 为了后期管理,这里所有的 LDIF 文件统一放大下面这个目录中
mkdir  /etc/openldap/my_ldif

vim /etc/openldap/my_ldif/init_root.ldif ,如下内容,其中的 olcRootPW 为通过 slappasswd 生成的密文,这里设置为 yore@123。

dn: olcDatabase={0}config,cn=config
changetype: modify
add: olcRootPW
olcRootPW: {SSHA}s2hLnvbtj2MmZtMSqp3PgEQwZMr/082K

dn: olcDatabase={2}hdb,cn=config
changetype: modify
add: olcRootPW
olcRootPW: {SSHA}s2hLnvbtj2MmZtMSqp3PgEQwZMr/082K

#修改Suffix
dn: olcDatabase={2}hdb,cn=config
changetype: modify
replace: olcSuffix
olcSuffix: dc=yore,dc=com

#修改RootDomain
dn: olcDatabase={2}hdb,cn=config
changetype: modify
replace: olcRootDN
olcRootDN: cn=root,dc=yore,dc=com

#修改访问权限
dn: olcDatabase={1}monitor,cn=config
changetype: modify
replace: olcAccess
olcAccess: {0}to * by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" read by dn.base="cn=root,dc=yore,dc=com" read by * none

执行下面的命令进行修改,并使之生效。

ldapmodify -H ldapi:// -Y EXTERNAL -f /etc/openldap/my_ldif/init_root.ldif

3.6.5 创建用户

下图显示了 LDAP 目录的管理树形结构:

LDAP认证RADIUS认证 ldap认证方式_CDH_04


/etc/openldap/my_ldif下创建一个基础用户的配置文件people_group_.ldif

dn: dc=yore,dc=com
o: sinosig com
dc: yore
objectClass: top
objectClass: dcObject
objectclass: organization

#dn: cn=root,dc=yore,dc=com
#cn: root
#objectClass: organizationalRole
#objectClass: Directory Manager

dn: ou=People,dc=yore,dc=com
ou: People
objectClass: top
objectClass: organizationalUnit

dn: ou=Group,dc=yore,dc=com
ou: Group
objectClass: top
objectClass: organizationalUnit

然后执行命令:

ldapadd -x -w "yore@123" -D "cn=root,dc=yore,dc=com" -f /etc/openldap/my_ldif/people_group_.ldif

接下来我们创建一个普通用户。在创建一个 /etc/openldap/my_ldif/user_impala_.ldif,文件内容如下,其中设置了uid、用户的密码(userPassword,可以是明文,也可以是密文),uidNumbergidNumber 是必须配置的,可以通过 id impala 获取。objectClass 可以查看/etc/openldap/schema

dn: uid=impala,ou=People,dc=yore,dc=com
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
cn: impala
sn: cdh
userPassword: cdhImpala_123
loginShell: /bin/bash
# id impala
uidNumber: 975
gidNumber: 971
homeDirectory: /var/lib/impala/ldap
#mail: test@test.com

接下来将这个用户添加到 LDAP中。执行命令:

ldapadd -x -w "yore@123" -D "cn=root,dc=yore,dc=com" -f /etc/openldap/my_ldif/user_impala_.ldif`

添加完用户可以通过下面的命令监测是否添加成功,如果可以在输出的结果中看到我们添加的用户,说明已添加成功。

ldapsearch -LLL -w "yore@123" -x -D "cn=root,dc=yore,dc=com" -H ldap://cdh1 -b "dc=yore,dc=com"

3.6.6 对用户的操作

通过前面几部分我们使用了一下命令,这些命令将会在这节进行详细的说明。

这部分涉及到对用户的运维,我们可以借助第三方开源软件实现的图形化运维管理工具进行,例如:PHPladpAdmin 管理工具开源的LDAP浏览器、LDAPAdmin、LAM 等。但是对于Linux系统运维人员,日常的操作几乎都是通过 Linux 命令完成,如果对命令比较熟悉,直接使用 OpenLDAP 自带的命令来维护效率会比较高,但是熟悉这些命令时存在难度的,所以这里主要介绍针对用户的常用命令。

3.6.6.1 OpenLDAP 管理命令汇总
  • ldapsearch: 搜索 OpenLDAP 目录树条目
  • ldapadd: 通过 LDIF 格式,添加目录树条目
  • ldapdelete: 删除 OpenLDAP 目录树条目
  • ldapmodify: 修改 OpenLDAP 目录树条目
  • ldapwhoami: 检验 OpenLDAP 用户的身份
  • ldapmodrdn: 修改 OpenLDAP 目录树 DN 条目
  • ldapcompare: 判断 DN 值和指定参数值是否属于同一个条目
  • ldappasswd: 修改 OpenLDAP 目录树用户条目实现密码重置
  • slaptest: 验证 slapd.conf 文件或 cn=配置目录(slapd.d)
  • slapindex: 创建 OpenLDAP 目录树索引,提高查询效率
  • slapcat: 将数据条目转换为 OpenLDAP 的 LDIF 文件

在下面的简介中,有些参数和前面的命令相同时,会省略部分的介绍。

3.6.6.2 ldapsearch,搜索目录树条目
# -b 指定查找的节点
# -D 指定查找的 DN,DN 是整个 OpenLDAP 树的主键
# -x 使用简单认证,不使用任何加密算法,例如:TLS、SASL 等相关加密算法
# -w 指定管理员的密码
# -W 在查询时提示输入管理员密码,如果不想输入密码,可以使用 -w user_passwd
# -H 使用 LDAP 服务器的 URI 地址进行操作
# -p 指定 OpenLDAP 监听的端口,默认为 389,如果是加密则端口为 636
# -LLL 禁止输出与过滤条件不匹配的信息
ldapsearch -x -D "cn=root,dc=yore,dc=com" -H ldap://cdh1 -b "dc=yore,dc=com"  -w "yore@123"
3.6.6.3 ldapadd,使用 LDIF 格式添加目录树条目
# -x 使用简单认证 
# -D 指定查找的 DN
# -w 直接指定密码
# -h 指定 ldaphost,可以使用 FQDN、IP
# -f LDIF 文件的路径
ldapadd -x -D "cn=root,dc=yore,dc=com" -w "yore@123" -h cdh1.yore.com -f hue_user00.ldif


# new_user00.ldif 如下
##########
dn: uid=hue,ou=People,dc=yore,dc=com
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
cn: hue
sn: cdh
# slappasswd 生成,hue123456
userPassword: {SSHA}MAZYEX6owgYZKUAzf2EYY3PXMz6tIstR
loginShell: /bin/bash
# id hue
uidNumber: 987
gidNumber: 983
homeDirectory: /usr/lib/hue/ldap
3.6.6.4 ldapdelete,删除 目录树条目
# -c 持续操作模式,例如,在操作过程中出现错误,也会继续进行之后的相关操作
# -D 指定查找的 DN
# -n 显示正在进行的相关操作
# -x 使用简单认证,
# -f 使用目标文件名作为命令的输入
# -y 指定含有密码的文件进行验证
# -r 递归删除

# ldapdelete -D "cn=root,dc=yore,dc=com"  -w "yore@123" -h cdh1.yore.com -x
3.6.6.5 ldapmodify,修改目录树条目
# -a 新增条目
# -n 显示正在进行的相关操作
# -v 显示详细输出结果
# -f 使用目标文件名(.ldif)作为命令的输入

ldapmodify -x -D "cn=root,dc=yore,dc=com" -w "yore@123" -H ldap://cdh1.yore.com -f modify.ldif

##########
# modify.ldif 文件内容如下
dn: uid=test,ou=people,dc=yore,dc=com
changetype: modify
replace: pwdReset
pwdReset: TRUE
3.6.6.6 ldapwhoami,验证服务器身份
ldapwhoami -x -D "cn=root,dc=yore,dc=com" -w "yore@123" -H ldap://cdh1.yore.com
3.6.6.7 ldapmodrdn,修改目录树 DN 条目
# -f 使用目标文件名作为命令的输入
# -r 删除 OpenLDAP 目录树中 rdn条目的唯一标识名称
# -P 这里指定的是 OpenLDAP 的版本号,比如 V2,V3
# -O 指定 SASL 安全属性
ldapmodrdn -x -D "cn=root,dc=yore,dc=com" -w "yore@123" -H ldap://cdh1.yore.com "uid=test,ou=people,dc=yore,dc.com"
3.6.6.8 ldapcompare,判断 DN 值和指定参数值是否属于同一个条目
# -P 这里指定的是 OpenLDAP 的版本号,比如 V2,V3
ldapcompare -x -D "cn=root,dc=yore,dc=com" -w "yore@123" -H ldap://cdh1.yore.com "uid=test,ou=people,dc=yore,dc.com" "uid:ada"
# 不匹配时显示 FALSE;匹配时显示 TRUE;给出的 DN 条目无法再目录树中检索到显示 UNDEFINED
3.6.6.9 ldappasswd,修改密码
# -S 提示用户输入新密码
# -s 指定密码
# -a 通过旧密码,自动生成新密码
# -A 提示输入就密码,自动生成新密码
ldappasswd -x -D "cn=root,dc=yore,dc=com" -w "yore@123" "uid=hue,ou=people,dc=yore,dc.com" -S
# 前面两次为设置新密码,最后提示输入管理员密码
3.6.6.10 slaptest, 验证 slapd.conf 文件
# -d 指定 debug 级别
# -f 检测的文件
# -F 检测的文件夹
slaptest -f /etc/openldap/slapd.conf
3.6.6.11 slapindex, 创建 OpenLDAP 目录树索引

可用来提高查询效率,减轻服务器响应压力,前提是 slapd 进程停止,否则会报错

# -d 指定 debug 级别
# -f 指定 OpenLDAP 配置文件,并创建索引
# -F 指定 OpenLDAP 数据库目录,并创建索引
3.6.6.12 slapcat, 数据条目转为 LDIF 文件

可用于备份,结合 slapdadd 指令进行恢复条目数据。

# -a 添加过滤选项
# -b 指定 suffix 路径,如 dc=yore,dc=com
# -d 指定 debug 级别
# -f 指定 OpenLDAP 配置文件
# -F 指定 OpenLDAP 数据库目录
# -c 出错时是否继续
# -v 输出详细信息
slapcat -v -l openldap.ldif

4 CDH

进入服务器环境,浏览器访问:http://${cloudera-scm-server-ip}:7180 。输入管理员的用户名和密码,进入CDH 的管理页面。

LDAP认证RADIUS认证 ldap认证方式_Hive_05

4.1 Hive开启 LDAP

在 CDH 的 Hive 配置处搜索 hive-site.xml 的 Hive 服务高级配置代码段,在其中添加配置项,如下图所示。

LDAP认证RADIUS认证 ldap认证方式_LDAP认证RADIUS认证_06

<property>
        <name>hive.security.authorization.enabled</name>
        <value>true</value>
        <description>enableor disable the hive clientauthorization</description>
    </property>

    <property>
        <name>hive.security.authorization.createtable.owner.grants</name>
        <value>ALL</value>
        <description>theprivileges automatically granted to the ownerwhenever a table gets created. Anexample like "select,drop" willgrant select and drop privilege to theowner of the table</description>
    </property>

    <property>
        <name>hive.server2.authentication</name>
        <value>LDAP</value>
        <description>
          Expects one of [nosasl, none, ldap, kerberos, pam, custom].
          Client authentication types.
            NONE: no authentication check
            LDAP: LDAP/AD based authentication
            KERBEROS: Kerberos/GSSAPI authentication
            CUSTOM: Custom authentication provider
                    (Use with property hive.server2.custom.authentication.class)
            PAM: Pluggable authentication module
            NOSASL:  Raw transport
        </description>
    </property>
    
    <property>
        <name>hive.server2.authentication.ldap.url</name>
        <value>ldap://cdh1</value>
    </property>

    <property>
        <name>hive.server2.authentication.ldap.baseDN</name>
        <value>ou=People,dc=yore,dc=com</value>
    </property>

4.2 Impala开启 LDAP

在 CDH 的 Impala配置处搜索 ldap,在其中添加配置项,如下图所示

  • 勾选 enable_ldap_auth
  • ldap_url:ldap://cdh1.yore.com:389
  • ldap_bind_pattern:uid=#UID,ou=People,dc=yore,dc=com
  • 在Impala 命令行参数高级配置代码段(安全阀)框中填入下面的参数(注意是双横线):--ldap_passwords_in_clear_ok=true

LDAP认证RADIUS认证 ldap认证方式_LDAP认证RADIUS认证_07


如果后面配置 Hue 后访问Impala 报如下错误,需要进行下面的配置。

User 'hue' is not authorized to delegate to 'hue'. User/group delegation is disabled.

Bad status for request TOpenSessionReq(username='hue', password=None, client_protocol=6, configuration={'idle_session_timeout': '900', 'impala.doas.user': u'hue'}): TOpenSessionResp(status=TStatus(errorCode=None, errorMessage="User 'hue' is not authorized to delegate to 'hue'. User/group delegation is disabled.\n", sqlState='HY000', infoMessages=None, statusCode=3), sessionHandle=TSessionHandle(sessionId=THandleIdentifier(secret='y\xb7\xd7/d\x82F\x7f\x9bV\x97\x11\xe5A@8', guid='\xd1\x85\xb0\x95\x94\xb7B1\x94g\xb1f\xfb\xb8\x89\x90')), configuration=None, serverProtocolVersion=5)

在 CDH 的 Impala配置处搜索 core-site.xml 的 Impala Daemon 高级配置代码段(安全阀),在其中添加配置项,如下图所示

<property>
        <name>hadoop.proxyuser.hue.hosts</name>
        <value>*</value>
    </property>

    <property>
        <name>hadoop.proxyuser.hue.groups</name>
        <value>*</value>
    </property>

在 CDH 的 Impala配置处搜索 Impala Daemon 命令行参数高级配置代码段,添加如下图所示

--authorized_proxy_user_config=hue=*

LDAP认证RADIUS认证 ldap认证方式_LDAP认证RADIUS认证_08

4.3 Hue开启 LDAP

当我们将Hive和Impala开启了LDAP后再在Hue 中查询数据,会报错而查询不到任何数据,因此我们也需要将Hue的LDAP也进行配置。打开CDH的管理页面,依次点击 Hue -> 配置 -> 搜索:ldap,我们写下面的配置项(可选,如果使用原先Hue管理用户则不改,如果使用 LDAP 管理和授权用户需要修改):

  • 身份验证后端backend:选择 desktop.auth.backend.LdapBackend
  • ldap_url:ldap://cdh1.yore.com:389
  • ldap_username_pattern:uid=<username>,ou=People,dc=yore,dc=com
  • base_dn:ou=People,dc=yore,dc=com
  • bind_dn:uid=hue,ou=People,dc=yore,dc=com
  • bind_password:hue123456

LDAP认证RADIUS认证 ldap认证方式_CDH_09

  • [必改项] 在Hue配置页面 搜索:hue_safety_valve_server.ini,添加如下配置
[beeswax]
close_queries=True
use_sasl=False
auth_username=hue
auth_password=hue123456
[impala]
server_host=cdh1.yore.com
server_interface=hiveserver2
server_port=21050
query_timeout_s=100
impersonation_enabled=True
auth_username=hue
auth_password=hue123456



5 使用

5.1 Hue

正如上一节最后所说,如果将 Hue开启 LDAP后,Hue原有的账号都将暂时无法使用,此时 的账号统一归 LDAP 管理,因此还需要在 LDAP 中添加这些用户,需要使用 Hue查看数据时,可以找管理员申请账号。如果Hue中LDAP相关的配置项没有改动,则原有的Hue中分配的用户可以继续使用,只会在Hue开启LDAP 后账号会统一归 LDAP 管理。

本次配置中为了保证旧有 Hue 账户能够继续使用,这里 Hue 中不设置LDAP,仅将Hive 和 Impala的LDAP认证信息给到 Hue,保证在 Hue中可以查询访问数据就行。

5.2 Beeline

Beeline 可以访问Hive 和Impala 的数据,添加了LDAP 之后,需要按照如下方式访问,执行脚本同理,加上 -f 参数即可。关于 Beeline 更详细的介绍可参阅我的另一篇 blog 「Beeline 的进阶使用」

# 访问 Hive 。
# 直接在其中指定用户名和密码参数即可,用户名和密码就是 LDAP 中创建的
beeline --color=true -d "org.apache.hive.jdbc.HiveDriver" -u "jdbc:hive2://cdh3:10000/default" -n hue -p hue123456


# 访问 Impala
# 注意 url 中必须要加上 UID、AuthMech、SSL、PWD参数
beeline --color=true -d "com.cloudera.impala.jdbc41.Driver" -u "jdbc:impala://cdh3:21050/reportmart;UID=hue;AuthMech=3;SSL=0;PWD=hue123456" \
--isolation=TRANSACTION_READ_UNCOMMITTED -n hue -p hue123456

如果使用 Beeline 连接 Hive 报如下错误,我们通过在其它节点远程连接是正常的,可以说明是 CDH 环境中的 beeline 的问题,我们可以直接再下载一个新的 beeline 工具在环境中连接使用即可。

Error: Could not open client transport with JDBC Uri: jdbc:hive2://cdh3:10000/default: Failed to open new session: java.lang.IllegalArgumentException: Cannot modify hive.exec.query.redactor.hooks at runtime. It is not in list of params that are allowed to be modified at runtime (state=08S01,code=0)

解决:下载 Apache Spark ,解压后,通过使用这个自带的 beeline 进行连接。

# 1 例如下载 spark-2.4.5-bin-hadoop2.7.tgz
wget https://mirrors.tuna.tsinghua.edu.cn/apache/spark/spark-2.4.5/spark-2.4.5-bin-hadoop2.7.tgz

# 2 解压
tar -zxf spark-2.4.5-bin-hadoop2.7.tgz -C /usr/local/
cd /usr/local/spark-2.4.5-bin-hadoop2.7/

# 3 使用
./bin/beeline --color=true -d "org.apache.hive.jdbc.HiveDriver" -u "jdbc:hive2://cdh3:10000/default" -n hue -p hue123456

如果在上面连接 hive 的过程中,显示如下HIVE_CLI_SERVICE_PROTOCOL_V8,且查询数据时直接退出,这个是由于 hive-jdbc 的版本过高,可以下载一个 hive-jdbc-1.1.1.jar

[root@cdh3 conf]# /usr/local/spark-2.4.5-bin-hadoop2.7/bin/beeline --color=true -d "org.apache.hive.jdbc.HiveDriver" -u "jdbc:hive2://cdh3:10000/default" -n hue -p hue123456
Connecting to jdbc:hive2://cdh3:10000/default
…… INFO jdbc.Utils: Supplied authorities: cdh3:10000
…… INFO jdbc.Utils: Resolved authority: cdh3:10000
…… INFO jdbc.HiveConnection: Will try to open client transport with JDBC Uri: jdbc:hive2://cdh3:10000/default
HIVE_CLI_SERVICE_PROTOCOL_V8
Beeline version 1.2.1.spark2 by Apache Hive

重新下载 hive-jdbc-1.1.1.jar,并将旧版本的 hive-jdbc重命名掉。

# 下载 hive-jdbc-1.1.1.jar,也可以下载 hive-jdbc-1.1.0.jar
wget https://repo1.maven.org/maven2/org/apache/hive/hive-jdbc/1.1.1/hive-jdbc-1.1.1.jar -P /usr/local/spark-2.4.5-bin-hadoop2.7/jars/

# 重命名旧 hive-jdbc
mv hive-jdbc-1.2.1.spark2.jar hive-jdbc-1.2.1.spark2.jar.back

如果再次连接出现如下错误:

0: jdbc:hive2://cdh3:10000/default> show databases;
Exception in thread "Thread-2" java.lang.NoSuchMethodError: org.apache.hive.service.cli.thrift.TFetchResultsReq.setFetchType(S)V
        at org.apache.hive.jdbc.HiveStatement.getQueryLog(HiveStatement.java:815)
        at org.apache.hive.jdbc.HiveStatement.getQueryLog(HiveStatement.java:786)
        at org.apache.hive.beeline.Commands.showRemainingLogsIfAny(Commands.java:944)
        at org.apache.hive.beeline.Commands.access$100(Commands.java:58)
        at org.apache.hive.beeline.Commands$1.run(Commands.java:920)
        at java.lang.Thread.run(Thread.java:748)
org.apache.hive.service.cli.thrift.TFetchResultsReq.setFetchType(S)V

我们重新在 spark-2.4.5-bin-hadoop2.7/jars/ 下添加hive-service-1.1.1.jar 即可

wget https://repo1.maven.org/maven2/org/apache/hive/hive-service/1.1.1/hive-service-1.1.1.jar -P /usr/local/spark-2.4.5-bin-hadoop2.7/jars/

5.3 impala-shell

这里配置上 LDAP 后,使用 impala-shell 访问 数据时需要我们输入密码认证。

# 注意,这里通过 -i 指定的 Impala的守护进程节点,端口为 21000,
# -l 指定认证方式为 LDAP
impala-shell --auth_creds_ok_in_clear -i cdh3:21000 -l -u impala

输入之后会提示输入 LDAP 用户的密码,只有密码认证通过才能成功登录。

LDAP认证RADIUS认证 ldap认证方式_Impala_10

5.4 关于 impala-shell执行脚本的问题

这里重点介绍一下,如何使用 impala-shell 在带有 LDAP 认证的情况下执行脚本,因为通过impala-shell --help命令,我们查看到的参数中并没有设置密码的参数选项,但是有LDAP 的使用 impala-shell 又需要我们输入密码。

不过我们在--help的参数中有一项会引起我们的注意,那就是 --ldap_password_cmd 参数,它只有如下的描述,但是这个参数如何使用呢?

--ldap_password_cmd=LDAP_PASSWORD_CMD
                        Shell command to run to retrieve the LDAP password
                        [default: none]

我们再次访问官网和源码,终于在这里获得了有用的信息,在 IMPALA-1934: Allow shell to retrieve LDAP password from shell cmd,看到了如下的提交说明:

Adds a new option --ldap_password_cmd that takes a string which is
executed as a shell command. The stdout results are used as the LDAP
password for this shell session.

Tests are added for the negative case (where the command fails for some
reason), but without tests for successful LDAP connections we can't test
the case where the password is correct.

所以我们直接在这个参数中跟上字符串,字符串中为获取密码的 shell 语句,因此通过 impala-shell 可以这样执行 sql 脚本。

impala-shell --auth_creds_ok_in_clear -l -i cdh3:21000 -u impala --ldap_password_cmd="echo -n 'cdhImpala_123'" -f ./my-impala.sql

5.5 JDBC 方式查询带 LDAP 的Hive 数据

pom.xml 中引入 hive 相关的依赖

<dependency>
    <groupId>org.apache.hadoop</groupId>
    <artifactId>hadoop-common</artifactId>
    <version>${hadoop.version}</version>
    <scope>${provided.scope}</scope>
</dependency>
<dependency>
    <groupId>org.apache.hive</groupId>
    <artifactId>hive-exec</artifactId>
    <version>${hive.version}</version>
    <scope>${provided.scope}</scope>
</dependency>
<dependency>
    <groupId>org.apache.hive</groupId>
    <artifactId>hive-jdbc</artifactId>
    <version>${hive.version}</version>
    <scope>${provided.scope}</scope>
</dependency>
<dependency>
    <groupId>org.apache.hive</groupId>
    <artifactId>hive-serde</artifactId>
    <version>${hive.version}</version>
    <scope>${provided.scope}</scope>
</dependency>

客户端例子如下,直接带上访问Hive数据库用户名和密码即可。

public static void main(String[] args) throws ClassNotFoundException, SQLException {
    // Hive 连接信息
    final String dirverName = "org.apache.hive.jdbc.HiveDriver";
    String url = "jdbc:hive2://cdh3:10000/hive_test";
    String user = "hiveuser01";
    String password = "abc123";

    // 带 LDAP 认证的,需要填写 Hive配置的 hive.server2.authentication.ldap.baseDN 的 LDAP 中 域的 用户名与密码
    user = "impala";
    password = "cdhImpala_123";

    Class.forName(dirverName);
    Connection conn;

    boolean hashPassword = true;
    if(hashPassword){ // 带密码的
        conn = DriverManager.getConnection(url, user, password);
    }else{ // 不带密码的
        conn = DriverManager.getConnection(url);
    }

    PreparedStatement ps = conn.prepareStatement("SHOW TABLES");
    ResultSet result = ps.executeQuery();

    List<String> tablesName = new ArrayList<>();
    while (result.next()){
        tablesName.add(result.getString(1));
    }
    ps.close();
    System.out.println(tablesName);
}

5.6 JDBC 方式查询带 LDAP 认证的Impala数据

pom.xml 中引入 hive 相关的依赖

<dependency>
    <groupId>com.cloudera.impala</groupId>
    <artifactId>jdbc</artifactId>
    <version>2.5.31</version>
</dependency>

<dependency>
    <groupId>org.apache.hive</groupId>
    <artifactId>hive-service</artifactId>
    <version>1.1.1</version>
    <exclusions>
        <exclusion>
            <groupId>org.apache.hive</groupId>
            <artifactId>hive-exec</artifactId>
        </exclusion>
    </exclusions>
</dependency>

<dependency>
    <groupId>org.apache.thrift</groupId>
    <artifactId>libthrift</artifactId>
    <version>0.12.0</version>
</dependency>

客户端例子如下,数据库驱动使用:com.cloudera.impala.jdbc41.Driver,在 url 中带上参数 ;UID=impala;AuthMech=3;SSL=0,在设置上访问Impala数据库的用户名和密码,以JDBC 方式访问是没问题的

package yore

import java.sql.{Connection, DriverManager, PreparedStatement, ResultSet}

/**
  * Impala JDBC
  *
  * Created by yore on 2019/5/20 06:46
  */
object ImpalaJdbcWithLDAP {
  private[yore] val JDBC_DRIVER: String = "com.cloudera.impala.jdbc41.Driver"
  private[yore] val URL = "jdbc:impala://cdh3:21050/reportmart;UID=impala;AuthMech=3;SSL=0"
  def main(args: Array[String]): Unit = {
    var conn: Connection = null
    var ps: PreparedStatement = null

    try{
      Class.forName(JDBC_DRIVER)
      conn = DriverManager.getConnection(URL, "impala", "cdhImpala_123")

      var sql = "show tables"

      ps = conn.prepareStatement(sql)
      val result: ResultSet = ps.executeQuery()

      val start = System.currentTimeMillis()
      while (result.next()){
        for(pos <- 1 to result.getMetaData.getColumnCount){
          print(result.getObject(pos) + "\t")
        }
        println()
      }
      val end = System.currentTimeMillis()
      println("-"*26 + s" Impala\n\t共花费:${(end - start).toDouble/1000} 秒")
    }catch {
      case e: Exception => e.printStackTrace()
    }finally {
      if(ps != null) ps.close()
      if(conn != null) conn.close()
      println("-"*26)
    }
  }
}

5.7 Spring Boot访问 LDAP 认证的Impala数据

这里特别需要注意的是,如果使用 com.cloudera.impala.jdbc41.DataSource 的方式实例化了一个 org.springframework.jdbc.core.JdbcTemplate,在url中必须严格将需要的参数全部都带上,格式如下,端口必须为21050UID必须和访问数据库设置的 user 一致AuthMech=3 表示访问数据库有密码认证、关闭SSL、PWD必须和访问数据的设置的user 对一个的 password 一致

jdbc:impala://cdh3:21050/reportmart;UID=hue;AuthMech=3;SSL=0;PWD=hue123456

application.yml 配置文件如下

impala:
  driverClass: com.cloudera.impala.jdbc41.Driver
  url: jdbc:impala://cdh3:21050/reportmart
  user: hue
  password: hue123456

使用 Spring JdbcTemplate 时的配置类代码如下:

import com.cloudera.impala.jdbc41.DataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;

@Configuration
public class ImpalaJdbcConfig {

    @Value("${impala.url}")
    private String impalaUrl;
    @Value("${impala.password}")
    private String password;
    @Value("${impala.user}")
    private String user;

    @Bean(name = {"impalaJdbcTemplate"})
    public JdbcTemplate getImpalaJdbcTemplate() {
        DataSource dataSource = new DataSource();
        String urlPerfect = String.format("%s;UID=%s;AuthMech=3;SSL=0;PWD=%s",this.impalaUrl, user, password);
        dataSource.setURL(urlPerfect);
        return new JdbcTemplate(dataSource);
    }
}