CDH集群与Kerberos集成手册

CDH集群与Kerberos集成手册

目录

一、 使用须知

二、 KDC服务器列表

三、 KDC Master安装配置

四、 KDC Slave安装配置

五、 主从功能验证

六、 KDC Master Slave定时同步脚本配置

七、 通过Cloudera Manager配置Kerberos

八、 连接有kerberos认证的hbase方法说明

1. 本手册仅适用于Cloudera 5.x的版本;

2. 集群所有节点都可以通过DNS服务或者hosts文件进行域名解析 ;

3. 手册仅针对MIT KDC进行配置说明,Active Directory用户请参考AD厂商的配置说明;

4. 配置时请给Cloudera Manager配置Kerberos管理员账户。 

  • KDC服务器列表

操作系统:

CentOS 7.4 x64

Kerberos主从配置

192.168.244.3   wyg01.para.com  wyg01  #KDC Master

192.168.244.4   wyg02.para.com  wyg02  #KDC Slave

192.168.244.5   wyg03.para.com  wyg03  #KDC Client

  • KDC Master安装配置

注:仅在KDC服务器上执行1-8步骤 

Kerberos的realms根据实际环境配置

数据湖集群realms为:PARA.COM

  1. KDC服务器安装(主从)

yum install -y krb5-server krb5-libs krb5-auth-dialog krb5-workstation(在三个节点上都执行此操作)

2. 修改/etc/krb5.conf配置 (Master)

vi /etc/krb5.conf

# Configuration snippets may be placed in this directory as well

includedir /etc/krb5.conf.d/

[logging]

 default = FILE:/var/log/krb5libs.log

 kdc = FILE:/var/log/krb5kdc.log

 admin_server = FILE:/var/log/kadmind.log

[libdefaults]

 default_realm = PARA.COM

 dns_lookup_realm = false

 dns_lookup_kdc = false

 ticket_lifetime = 24h

 renew_lifetime = 7d

 forwardable = true

# rdns = false

# pkinit_anchors = FILE:/etc/pki/tls/certs/ca-bundle.crt

# default_realm = EXAMPLE.COM

# default_ccache_name = KEYRING:persistent:%{uid}

[realms]

 PARA.COM = {

  kdc = wyg01.para.com

  kdc = wyg02.para.com

  admin_server = wyg01.para.com

 }

[domain_realm]

 .para.com = PARA.COM

 para.com = PARA.COM

3. 修改/var/kerberos/krb5kdc/kdc.conf

vi /var/kerberos/krb5kdc/kdc.conf

[kdcdefaults]

 kdc_ports = 88

 kdc_tcp_ports = 88

[realms]

 PARA.COM = {

  #master_key_type = aes256-cts

  max_renewable_life = 7d 0h 0m 0s

  acl_file = /var/kerberos/krb5kdc/kadm5.acl

  dict_file = /usr/share/dict/words

  admin_keytab = /var/kerberos/krb5kdc/kadm5.keytab

  supported_enctypes = aes256-cts:normal aes128-cts:normal des3-hmac-sha1:normal arcfour-hmac:normal camellia256-cts:normal camellia128-cts:normal des-hmac-sha1:normal des-cbc-md5:normal des-cbc-crc:normal

 }

4. 修改/var/kerberos/krb5kdc/kadm5.acl

*/admin@PARA.COM        *

5. 创建Kerberos数据库 

创建数据库命令:

[root@wyg01 krb5kdc]# kdb5_util create -r PARA.COM -s

Loading random data

Initializing database '/var/kerberos/krb5kdc/principal' for realm 'PARA.COM',

master key name 'K/M@PARA.COM'

You will be prompted for the database Master Password.

It is important that you NOT FORGET this password.

Enter KDC database master key:   #密码:para.123!

Re-enter KDC database master key to verify:  #确认密码:para.123!

[root@wyg01 krb5kdc]#

[root@wyg01 krb5kdc]#

6. 将Kerberos服务添加到启动项,并启动服务

设置开启自启动:

# systemctl enable krb5kdc

# systemctl enable kadmin

启动服务:

# systemctl start krb5kdc

# systemctl start kadmin

7. 创建Kerberos的管理员的账户 

kadmin.local

kadmin.local:  addprinc admin/admin@PARA.COM

*请记住输入的Kerberos管理员密码(密码:para.123!)。 

8. 测试Kerberos管理员账户认证

执行认证:

[root@wyg01 krb5kdc]# kinit admin/admin@PARA.COM

Password for admin/admin@PARA.COM: (密码:para.123!

[root@wyg01 krb5kdc]#

查看是否认证成功

[root@wyg01 krb5kdc]# klist

Ticket cache: FILE:/tmp/krb5cc_0

Default principal: admin/admin@PARA.COM

Valid starting       Expires              Service principal

05/02/2018 18:28:18  05/03/2018 18:28:18  krbtgt/PARA.COM@PARA.COM

        renew until 05/09/2018 18:28:18

[root@wyg01 krb5kdc]#

  • KDC Slave安装配置

在wyg01上创建host  keytab 文件

[root@wyg01 krb5kdc]# kadmin.local 

kadmin.local:  addprinc -randkey host/wyg01.para.com   #添加principal

kadmin.local:  ktadd host/wyg01.para.com             #生成keytab文件

kadmin.local:  

kadmin.local:  addprinc -randkey host/wyg02.para.com

kadmin.local:  ktadd host/wyg02.para.com

kadmin.local:  

执行上述2个ktadd导出命令后会生成1个krb5.keytab文件,里面包含两个principal的信息,全路径为/etc/krb5.keytab。

将此krb5.keytab拷贝到KDC Slave服务器/etc/下。

# scp /etc/krb5.keytab root@wyg02.para.com:/etc/

     (7-2)将wyg01上的几个文件拷贝到从服务器,
文件: krb5.conf、kdc.conf、kadmin5.acl、master key stash file(.k5.XXXXX)

# scp /etc/krb5.conf  root@wyg02.para.com:/etc/
进入如下目录:

# cd /var/kerberos/krb5kdc

# scp kdc.conf kadm5.acl .k5.PRAR.COM root@wyg02.para.com:/var/kerberos/krb5kdc/

在slave服务器上创建kpropd.acl文件

[root@wyg02 krb5kdc]# cd /var/kerberos/krb5kdc

[root@wyg02 krb5kdc]# touch /var/kerberos/krb5kdc/ kpropd.acl

[root@wyg02 krb5kdc]#

[root@wyg02 krb5kdc]# vi kpropd.acl

host/wyg01.para.com@PARA.COM   加上这类

host/wyg02.para.com@PARA.COM   加上这类

[root@wyg02 ~]# cat  /var/kerberos/krb5kdc/kpropd.acl

host/wyg01.para.com@PARA.COM

host/wyg02.para.com@PARA.COM

Slave节点上也需要创建数据库:

[root@wyg02 ~]# kdb5_util create –r PARA.COM -s

设置密码

在slave上启动kpropd服务

# kpropd -S

#service krb5kdc start

 至此,slave上的kdc服务还不能启动,因为无kdc的database数据

systemctl enable krb5kdc

systemctl stop krb5kdc

8)在master上将相关数据同步到slave上

导出数据库:

# kdb5_util dump /var/kerberos/krb5kdc/slave_datatrans

同步到KDC Slave:

# kprop -f /var/kerberos/krb5kdc/slave_datatrans wyg02.para.com

成功后,会出现类似以下信息:
Database propagation to wyg02.para.com: SUCCEEDED

以上命令,可以封装成一个bash,定时运行,即定时更新slave上的database。

如果未出现SUCCEEDED

(1)如果出现错误:

kprop: Client not found in Kerberosdatabase while getting initial ticket

解决:

在master上添加规则

    kadmin: addprinc  -randkey  host/kerberos2.example.com  #添加principal

    kadmin:ktadd host/kerberos2.example.com    #生成keytab文件

(2)如果出现错误:

[root@kerberos security]#

 kprop -f /var/kerberos/krb5kdc/slave_datatrans  kerberos2.example.com -P 749 -s -d

kprop: Server rejected authentication(during sendauth exchange) while authenticating to server

kprop: Decrypt integrity check failedsignalled from server

Error text from server: Decrypt integritycheck failed

更换命令:

 [root@kerberos ~]# kdb5_util dump/var/kerberos/krb5kdc/kdc.dump

 [root@kerberos~]#kprop -f/var/kerberos/krb5kdc/kdc.dump kerberos2.example.com

9)slave上/var/kerberos/krb5kdc/会多出一些文件,如:

from_master、principal、pricipal.kadm5、principal.kadmin5.lock、principal.ok

[root@wyg02~]$ ls -lart /var/kerberos/krb5kdc/

total 60

drwxr-xr-x 4 root root  4096 Sep 25 22:40 ..

-rw------- 1 root root   442 Sep 26 18:40 kdc.conf

-rw------- 1 root root    13 Sep 26 18:40 kadm5.acl

-rw------- 1 root root    67 Sep 26 18:42 .k5.NJ

-rw-r--r-- 1 root root    50 Sep 26 19:06 kpropd.acl

-rw------- 1 root root  8704 Sep 27 10:29 from_master

-rw------- 1 root root  8192 Sep 27 10:29 principal.kadm5

-rw------- 1 root root     0 Sep 27 10:29 principal.kadm5.lock

-rw------- 1 root root 16384 Sep 27 10:29 principal

drwxr-xr-x 2 root root  4096 Sep 27 10:29 .

-rw------- 1 root root     0 Sep 27 10:29 principal.ok

[appuser@share-mysql02 ~]$

[appuser@share-mysql02 ~]$

10)至此,可以启动slave上的kdc服务

[root@wyg02 ~]# systemctl start krb5kdc

查看状态:

[root@wyg02 ~]# systemctl status krb5kdc

● krb5kdc.service - Kerberos 5 KDC

   Loaded: loaded (/usr/lib/systemd/system/krb5kdc.service; disabled; vendor preset: disabled)

   Active: active (running) since Wed 2017-09-27 10:35:44 CST; 7s ago

  Process: 3579 ExecStart=/usr/sbin/krb5kdc -P /var/run/krb5kdc.pid $KRB5KDC_ARGS (code=exited, status=0/SUCCESS)

 Main PID: 3580 (krb5kdc)

   CGroup: /system.slice/krb5kdc.service

           └─3580 /usr/sbin/krb5kdc -P /var/run/krb5kdc.pid

Sep 27 10:35:44 share-mysql02.nj systemd[1]: Starting Kerberos 5 KDC...

Sep 27 10:35:44 share-mysql02.nj systemd[1]: Started Kerberos 5 KDC.

[root@wyg02 ~]#

  • 主从功能验证

将KDC master上的/etc/krb5.conf拷贝到第三台独立的服务器上,注意此服务器需要安装有KDC Client

# scp /etc/krb5.conf wyg03.para.com:/etc/

测试主从是否生效(成功)

    1)从第三台服务器,使用kinit获取ticket,正常情况下会从master上获取

    2)关闭master上的kdc服务

    3)再次从第三台服务器上,使用kinit 获取ticket,如果成功,说明生效。

       也可以观察kdc的日志,在 /var/log/krb5kdc.log

  1. 默认KDC Master启动情况下,执行认证

[root@wyg01]# ifconfig | grep 10.133

        inet 10.133.60.24  netmask 255.255.255.0  broadcast 10.133.60.255

[root@swyg01]#

[root@wyg01]# kinit admin/admin@PARA.COM

Password for admin/admin@PARA.COM:    #密码:para.123!

[root@wyg01]#

检查是否认证成功:

[root@wyg01]# klist

Ticket cache: KEYRING:persistent:0:0

Default principal: admin/admin@PARA.COM

Valid starting       Expires              Service principal

09/27/2017 10:53:06  09/28/2017 10:53:06  krbtgt/PARA.COM@PARA.COM

[root@wyg01]#

[root@wyg01]#

  1. 停止KDC Master服务

[root@wyg01 ~]# systemctl stop krb5kdc

[root@wyg01 ~]#

[root@wyg01 ~]# systemctl status krb5kdc

● krb5kdc.service - Kerberos 5 KDC

   Loaded: loaded (/usr/lib/systemd/system/krb5kdc.service; enabled; vendor preset: disabled)

   Active: inactive (dead) since Wed 2017-09-27 10:54:02 CST; 4s ago

  Process: 29622 ExecStart=/usr/sbin/krb5kdc -P /var/run/krb5kdc.pid $KRB5KDC_ARGS (code=exited, status=0/SUCCESS)

 Main PID: 29623 (code=exited, status=0/SUCCESS)

Sep 26 17:54:04 share-mysql01.nj systemd[1]: Starting Kerberos 5 KDC...

Sep 26 17:54:04 share-mysql01.nj systemd[1]: Started Kerberos 5 KDC.

Sep 27 10:54:02 share-mysql01.nj systemd[1]: Stopping Kerberos 5 KDC...

Sep 27 10:54:02 wyg01.para.com systemd[1]: Stopped Kerberos 5 KDC.

[root@wyg01 ~]#

  1. 再次通过第三台服务器执行认证

先销毁原凭证:

[root@wyg03]# kdestroy

[root@wyg03]#

[root@wyg03]# klist

klist: Credentials cache keyring 'persistent:0:0' not found

[root@wyg03]#

[root@wyg03]#

[root@wyg03]#

重新执行认证:

[root@wyg03]# kinit admin/admin@PARA.COM

Password for admin/admin@PARA.COM:    #密码:Root123!

[root@wyg03]#

检查认证结果,可以看到认证成功,时间10:54:17,如:

[root@wyg03]# klist

Ticket cache: KEYRING:persistent:0:0

Default principal: admin/admin@PARA.COM

Valid starting       Expires              Service principal

09/27/2017 10:54:17  09/28/2017 10:54:17  krbtgt/PARA.COM@PARA.COM

[root@wyg03]#

查看对应KDC Slave主机的kdc日志,可以看到日志在10:54:17有认证记录:

[root@wyg02 ~]$

[root@wyg02 ~]$ sudo su -

Last login: Wed Sep 27 10:35:34 CST 2017 on pts/0

[root@wyg02 ~]# tail -n 50 /var/log/krb5kdc.log

otp: Loaded

Sep 27 10:35:44 share-mysql02.nj krb5kdc[3579](info): setting up network...

Sep 27 10:35:44 share-mysql02.nj krb5kdc[3579](info): listening on fd 9: udp 0.0.0.0.88 (pktinfo)

krb5kdc: setsockopt(10,IPV6_V6ONLY,1) worked

Sep 27 10:35:44 share-mysql02.nj krb5kdc[3579](info): listening on fd 10: udp ::.88 (pktinfo)

krb5kdc: setsockopt(11,IPV6_V6ONLY,1) worked

Sep 27 10:35:44 share-mysql02.nj krb5kdc[3579](info): listening on fd 12: tcp 0.0.0.0.88

Sep 27 10:35:44 share-mysql02.nj krb5kdc[3579](info): listening on fd 11: tcp ::.88

Sep 27 10:35:44 share-mysql02.nj krb5kdc[3579](info): set up 4 sockets

Sep 27 10:35:44 share-mysql02.nj krb5kdc[3580](info): commencing operation

Sep 27 10:54:17 share-mysql02.nj krb5kdc[3580](info): AS_REQ (6 etypes {18 17 16 23 25 26}) 10.133.60.24: ISSUE: authtime 1506480857, etypes {rep=18 tkt=18 ses=18}, admin/admin@NJ for krbtgt/PARA.COM@PARA.COM

[root@wyg02 ~]#

[root@wyg02 ~]#

至此,说明KDC主从配置已经成功。

这时要开启wyg01.para.com节点的kdc服务

 systemctl start krb5kdc

systemctl status krb5kdc

  • KDC Master Slave定时同步脚本配置

创建同步脚本目录

[root@wyg01 kdcsync_scripts]# mkdir /var/kerberos/krb5kdc/kdcsync_scripts

[root@wyg01 kdcsync_scripts]# cd /var/kerberos/krb5kdc/kdcsync_scripts

创建同步脚本

 [root@wyg01 kdcsync_scripts]# cat kdcsync.sh

#!/bin/sh

curDir=$(cd "$(dirname "$0")"; pwd)

LOGFILE=$curDir/kdcsync.log

kdclist="wyg02.para.com"

echo "---------- `date '+%Y-%m-%d %H:%M:%S'` ----------" | tee -a $LOGFILE

echo "kdb5_util dump /var/kerberos/krb5kdc/slave_datatrans" | tee -a $LOGFILE

/sbin/kdb5_util dump /var/kerberos/krb5kdc/slave_datatrans 2>&1 | tee -a $LOGFILE

ls -l /var/kerberos/krb5kdc/slave_datatrans | tee -a $LOGFILE

for kdc in $kdclist

do

    echo "kprop -f /var/kerberos/krb5kdc/slave_datatrans $kdc" | tee -a $LOGFILE

    /sbin/kprop -f /var/kerberos/krb5kdc/slave_datatrans $kdc 2>&1 | tee -a $LOGFILE

done

[root@share-mysql01 kdcsync_scripts]#

chmod +x  kdcsync.sh

crontab 定时任务设定为每天12点01分执行同步脚本:

crontab -e编辑

[root@wyg01 kdcsync_scripts]# crontab -l

#kdc master slave db sync

01 12 * * * sh /var/kerberos/krb5kdc/kdcsync_scripts/kdcsync.sh

[root@wyg01 kdcsync_scripts]#

七、 所有机器安装客户端

给所有集群的节点安装Kerberos客户端,包括Cloudera Manager Server(所有节点上操作) 

yum install -y krb5-libs krb5-workstation

10. 在Cloudera Manager Server节点上安装额外的包 

yum install -y openldap-clients

11. 将KDC Server上的krb5.conf文件拷贝到所有客户端上 (三台主机文件内容其实是一样的)

scp /etc/krb5.conf wyg03.para.com:/etc/

  • 通过Cloudera Manager配置Kerberos

1. 在所有主机上安装JCE策略文件 (注意,安装CM Agent时如果勾选安装,不需要在此安装。)

在Cloudera Manager管理主页面上,进入“主机”页面,点击“重新运行升级向导”,在“JDK安装选项”向导页中,选择如下选项:

 

2. 如下,在KDC中给Cloudera Manager添加管理员账号cloudera-scm/admin@NJ

[root@wyg01 ~]# kadmin.local 

kadmin.local:  addprinc cloudera-scm/admin@PARA.COM

WARNING: no policy specified for cloudera-scm/admin@PARA.COM; defaulting to no policy

Enter password for principal "cloudera-scm/admin@PARA.COM":         #密码:para.123!

Re-enter password for principal "cloudera-scm/admin@PARA.COM":      #密码:para.123!

Principal "cloudera-scm/admin@PARA.COM" created.

kadmin.local:

*请记住给Cloudera Manager Server创建的账号和密码(para.123!)。

3. 在Cloudera Manager的首页点击集群的下拉箭头按钮 → 选择“启用Kerberos” 

 

4. 进入启用Kerberos的欢迎界面,会列出一些检查项,确保这些准备工作都已经完成。

 

 

另外,如果在启用Kerberos之前已经配置了YARN的HA,则需要在启用kerberos之前清空Zookeeper中YARN配置的StateStore znode。停止YARN服务,并在YARN服务的“操作”菜单下选择“Format State Store”。

5. 配置相关的KDC信息,包括类型、KDC服务器、KDC Realm、加密类型以及待创建的Service Principal(hdfs,yarn,,hbase,hive等)的更新生命期等。 

注意:实际环境中,

KDC Server主机一栏,填写对应的KDC主机名,如此处为wyg01.para.com

Kerberos安全域一栏,填写对应的域名称,具体看前面的kdc配置,如此处为PARA.COM

 

 

 

 

6. 不建议选择让Cloudera Manager来管理krb5.conf

 

7. 输入Cloudera Manager的Kerbers管理员账号,一定得和之前创建的账号一致;应该是cloudera-scm/admin@PARA.COM,而不是cloudera-scm@PARA.COM ,密码为上面创建的para.123! ,如:

 

点击右下角继续:

 

点击右下角继续,确认Kerberos服务范围:

 

选取MIT KDC,填写Kerberos的加密类型,RAELMS名称及服务地址。加密类型增加aes128-cts,aes256-cts,des-cbc-crc三类。

9. 修改DataNode收发器端口和HTTP Web UI端口,可以就用Cloudera Manager推荐的值并重启集群: 

 

10. 然后会进入这样一个Kerberos启用界面 

 

11. 成功启用Kerberos

 

  • 创建常用服务keytab 

登录192.168.244.3,创建hdfs,yarn,hive,hbase服务对应的keytab:

登陆kadmin:

[root@wyg01 ~]# kadmin.local

Authenticating as principal root/admin@PARA.COM with password.

kadmin.local:

kadmin.local:  

添加hdfs账户:

kadmin.local:  addprinc -randkey hdfs@PARA.COM

WARNING: no policy specified for hdfs@NJ; defaulting to no policy

Principal "hdfs@PARA.COM" created.

kadmin.local:

到处keytab:

kadmin.local:  xst -norandkey -k hdfs.keytab hdfs@PARA.COM

kadmin.local:  

kadmin.local:  exit

[root@wyg01 ~]#

执行导出命令后,会在用户当前目录看到导出的hdfs.keytab文件:

[root@wyg01 ~]# ls

anaconda-ks.cfg  hdfs.keytab  post.log

[root@wyg01 ~]#

测试使用hdfs认证 

[root@wyg01 ~]# kinit -kt hdfs.keytab hdfs

[root@wyg01 ~]# klist

Ticket cache: FILE:/tmp/krb5cc_0

Default principal: hdfs@PARA.COM

Valid starting       Expires              Service principal

09/27/2017 15:31:33  09/28/2017 15:31:33  krbtgt/PARA.COM@PARA.COM

[root@wyg01 ~]# kdestroy

[root@wyg01 ~]#

其余用户参照上面依次创建即可。

kadmin.local:  addprinc -randkey yarn@PARA.COM

kadmin.local:  xst -norandkey -k yarn.keytab yarn@PARA.COM

kadmin.local:  addprinc -randkey hive@PARA.COM            

kadmin.local:  xst -norandkey -k hive.keytab hive@PARA.COM   

kadmin.local:  addprinc -randkey hbase@PARA.COM           

kadmin.local:  xst -norandkey -k hbase.keytab hbase@PARA.COM  

  • 连接有kerberos认证的hbase方法说明

针对开启了kerberos认证后,如果开发的应用程序需要连接hbase,则需要对应用程序添加相关kerberos认证配置。

如下HbaseKerberos.java为hbase 过kerberos实例代码;

Configuration conf = HBaseConfiguration.create();

String hbaseKrbUser,hmasterPrincipal,hregionserverPrincipal,krbFile,keytabFile;

Properties properties = new Properties();

properties.load(new FileInputStream(new File("conf/dataPut.properties")));

String krbEnable = properties.getProperty("krbEnable", "false").toLowerCase();

//获取kerberos配置

if(krbEnable.equals("true")){

hmasterPrincipal = properties.getProperty("hmasterPrincipal");

hregionserverPrincipal = properties.getProperty("hregionserverPrincipal");

krbFile = properties.getProperty("krbFile");

keytabFile = properties.getProperty("keytabFile");

hbaseKrbUser = properties.getProperty("hbaseKrbUser");

System. setProperty("java.security.krb5.conf", krbFile);

}

conf.set("hbase.zookeeper.quorum", properties.getProperty("hbase_zookeeper_quorum"));

conf.set("hbase.zookeeper.property.clientPort", properties.getProperty("hbase_zkPort"));

if(krbEnable.equals("true")){

//Kerberos 认证

conf.set("hadoop.security.authentication" , "Kerberos" );

conf.set("hbase.security.authentication" , "Kerberos" );

conf.set("hbase.zookeeper.client.keytab.file" ,keytabFile);

       

conf.set("hbase.master.kerberos.principal",hmasterPrincipal);

conf.set("hbase.master.keytab.file" ,keytabFile);

conf.set("hbase.regionserver.kerberos.principal",hregionserverPrincipal);

conf.set("hbase.regionserver.keytab.file" ,keytabFile);

UserGroupInformation.setConfiguration(conf);

    UserGroupInformation.loginUserFromKeytab(hbaseKrbUser,keytabFile);

}

如下dataPut.properties为配置文件;

#######HBase configuration###############################

#COMP

hbase_zookeeper_quorum=192.168.244.3,192.168.244.4,192.168.244.5

#Old cluster

#hbase_zookeeper_quorum=192.168.244.3,192.168.244.4,192.168.244.5

hbase_zkPort=2181

#######HBase kerberos configuration######################

krbEnable=true

hbasePrincipal=hbase/_HOST@PARACOM

hmasterPrincipal=hbase/_HOST@PARA.COM

hregionserverPrincipal=hbase/_HOST@PARA.COM

krbFile=conf/krb5.conf

keytabFile=conf/hbase.keytab

hbaseKrbUser=hbase@PARA.COM

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值