Kerberos简介、安装及与其它服务的集成和使用

目录



1 简介

Kerberos 于1983年被开发为 MIT 雅典娜计划的身份验证引擎。1987年以开源形式发布,1993年成为IETF标准。

Kerberos 最初是在 1980 年代为麻省理工学院的 Athena 项目开发的,现已发展成为现代计算机网络中部署最广泛的用于身份验证和授权的系统。Kerberos 当前随所有主要的计算机操作系统一起提供,并且具有特殊的位置,使其成为分布式认证和授权问题的通用解决方案,该问题允许在企业联盟( federated enterprises)与对等社区(peer-to-peer communities)之间进行“单点登录”。MIT已开发并维护适用于 Apple Macintosh,Windows 和 Unix 操作系统的 Kerberos 软件的实现。

1.1 官方文档连接

这里该出目前官网最新的版本 1.19 的文档连接 MIT Kerberos Documentation(1.19-prerelease)

1.2 A guided tour of Kerberos: Tutorial

这里推荐查看 Fulvio Ricciardi 撰写 《KERBEROS PROTOCOL TUTORIAL》,这篇文档是快速了解 Kerberos 的一篇非常棒的指南教程,原文地址为 http://www.kerberos.org/software/tutorial.html ,也可以直接访问原文地址进行查看,也可以查看我对这份文档的译文 「 A guided tour of Kerberos: Tutorial 」

重点理解其中的这张图,下面的安装也将按照这个来进行安装和配置。
Kerberos 请求过程图


2 安装

系统环境为 CentOS 7 64位, CPU 为Intel,支持的指令集为 x86_64。

[root@cdh1 ~]# cat /etc/redhat-release
CentOS Linux release 7.7.1908 (Core)
[root@cdh1 ~]# lscpu | grep -i Architecture
Architecture:          x86_64
[root@cdh1 ~]#

2.1 下载

如果可以连接网络,也可以直接通过 yum 方式安装:yum install krb5-server krb5-libs krb5-auth-dialog krb5-workstation,或者通过配置内网可以访问的yum源。下面以rpm安装方式为例。

# 1 卸载旧版本 Kerberos
# 因为可能系统会带有这个包,建议如果有直接卸载,否则可能后期安装会因为版本问题而报错
rpm -qa | grep -E "krb5|libkadm5"
rpm -e --nodeps xxx

## 2 下载二进制制包形式(以 CentOS 7 x86 64 位 为例)
## 访问: https://pkgs.org/download/krb5-libs
## 下载 krb5-libs-*.rpm
wget http://mirror.centos.org/centos/7/updates/x86_64/Packages/krb5-libs-1.15.1-37.el7_7.2.x86_64.rpm
## 下载 krb5-workstation-*.rpm
wget http://mirror.centos.org/centos/7/updates/x86_64/Packages/libkadm5-1.15.1-37.el7_7.2.x86_64.rpm
wget http://mirror.centos.org/centos/7/updates/x86_64/Packages/krb5-workstation-1.15.1-37.el7_7.2.x86_64.rpm
## 下载 krb5-server-*.rpm
wget http://mirror.centos.org/centos/7/updates/x86_64/Packages/krb5-server-1.15.1-37.el7_7.2.x86_64.rpm

## 3 下载完毕后,查看如下:
[root@cdh1 software]# ll
total 2856
-rw-r--r-- 1 root root  824024 Sep 14  2019 krb5-libs-1.15.1-37.el7_7.2.x86_64.rpm
-rw-r--r-- 1 root root 1070820 Sep 14  2019 krb5-server-1.15.1-37.el7_7.2.x86_64.rpm
-rw-r--r-- 1 root root  836076 Sep 14  2019 krb5-workstation-1.15.1-37.el7_7.2.x86_64.rpm
-rw-r--r-- 1 root root  182108 Sep 14  2019 libkadm5-1.15.1-37.el7_7.2.x86_64.rpm

2.2 KDC 节点的安装

2.2.1 安装

# 安装前面下载的rpm 包 
# (KDC 安装krb5-libs、krb5-server、krb5-workstation,其他节点安装 krb5-libs、krb5-workstation)
# KDC 需要安装 krb5-lib-1.xx.x, krb5-workstation-1.xx.x, krb5-server-1.xx.x
# KDC 从节点上只需要安装 krb5-lib-1.xx.x, krb5-workstation-1.xx.x
# 如果安装的时候有依赖上的检查冲突,可以加上参数 --nodeps --force
# 
# 如果报 libkadm5,可以尝试重新安装或升级 libkadm5
#  否则会有如下的错误
#   error: Failed dependencies:
#           krb5-libs(x86-64) = 1.15.1-37.el7_7.2 is needed by krb5-workstation-1.15.1-37.el7_7.2.x86_64
#           libkadm5(x86-64) = 1.15.1-37.el7_7.2 is needed by krb5-workstation-1.15.1-37.el7_7.2.x86_64
rpm -ivh libkadm5-1.15.1-37.el7_7.2.x86_64.rpm
rpm -ivh krb5-libs-1.15.1-37.el7_7.2.x86_64.rpm
rpm -ivh krb5-workstation-1.15.1-37.el7_7.2.x86_64.rpm
rpm -ivh krb5-server-1.15.1-37.el7_7.2.x86_64.rpm

错误1:在安装时如果报如下的错误,需要下载安装 words 插件,因为有些应用或数据库会使用这个来检查单词的拼写,或者密码检查器会使用这个来查找有误的密码。

error: Failed dependencies:
        /usr/share/dict/words is needed by krb5-server-1.15.1-37.el7_7.2.x86_64

解决:如果可以使用yum,直接安装即可 yum install words。这里给出离线安装方式:

# 1 查看是否有 words
rpm -qa | grep words

# 2 下载 words 包 
wget http://mirror.centos.org/centos/7/os/x86_64/Packages/words-3.0-22.el7.noarch.rpm

# 3 安装。安装成功后会在 /usr/share/dict/words 有一个词文件。
rpm -ivh words-3.0-22.el7.noarch.rpm

安装的过程如下:
KDC 节点安装图

2.2.2 配置 /var/kerberos/krb5kdc/kdc.conf

执行完上一步的安装之后,在 /var/kerberos 下会有生成配置文件,下面我们需要修改 /var/kerberos/krb5kdc/kdc.conf。只在 KDC 机器上修改,配置如下,这里对其中某些参数说明如下:CDH.COM:设定 realm ,可以随意设置,但一般和公司域名相关,大小写敏感且一般是大写,这里以 CDH.COM 为例。同时需要注意对加密方式的设置,如果需要使用 aes256-cts 加密方式,请确保环境JDK支持这种加密,如果没有解决方式可以看注释。

[kdcdefaults]
 kdc_ports = 88
 kdc_tcp_ports = 88

[realms]
 CDH.COM = {
   # JDK 8 (至少在 jdk 1.8 _152 之前的)可能不支持,如果使用中发现异常:java.security.InvalidKeyException: Illegal key size,
   # 方法1,可以将 aes256-cts 去点,保留 aes128-cts
   # 方法2,或者下载官方提供的 jce_policy-8.zip 包,解压后将 local_policy.jar 和 US_export_policy.jar 覆盖JDK安装目录下的 jre\lib\security 下的两个文件
   #       每个版本的路径可能稍微有差别,只要找到 unlimited 下的
   #       下载地址 http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html
   #master_key_type = aes256-cts
   acl_file = /var/kerberos/krb5kdc/kadm5.acl
   dict_file = /usr/share/dict/words
   admin_keytab = /var/kerberos/krb5kdc/kadm5.keytab
   max_renewable_life = 7d 0h 0m 0s
   supported_enctypes = 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
 }

2.2.3 配置 /var/kerberos/krb5kdc/kadm5.acl

Realme 改为上面配置的名字CDH.COM。这样名称匹配 */[email protected] 的都会认为 admin,权限是 *,代表全部权限。

 */[email protected] *

2.2.4 配置 /etc/krb5.conf

其中 cdh2.yore.com 为 KDC 服务的主机名。


# 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 = CDH.COM
 dns_lookup_realm = false
 dns_lookup_kdc = false
 ticket_lifetime = 24h
 renew_lifetime = 7d
 forwardable = true
 #rdns = false
 #pkinit_anchors = /etc/pki/tls/certs/ca-bundle.crt
# default_realm = EXAMPLE.COM
 #default_ccache_name = KEYRING:persistent:%{uid}

[realms]
 CDH.COM = {
  kdc = cdh2.yore.com
  admin_server = cdh2.yore.com
 }

[domain_realm]
.cdh2.yore.com = CDH.COM
cdh2.yore.com = CDH.COM

2.2.5 创建 Kerberos 数据库

# 1 创建/初始化 Kerberos database
# 当遇到问题,可能需要执行: /usr/sbin/kdb5_util -r CDH.COM -m destory -f。 
#            删除  /var/kerberos/krb5kdc/principal*
# 
# 期间会要求输入密码。kdc123
/usr/sbin/kdb5_util create -s -r CDH.COM

# 2 查看生成的文件
# 前两个是我们前两步设置的,后面的 principal* 就是本次生成的
[root@cdh1 software]# ll /var/kerberos/krb5kdc/
total 24
-rw-r--r-- 1 root root   19 Mar 25 21:41 kadm5.acl
-rw-r--r-- 1 root root  488 Mar 25 21:42 kdc.conf
-rw------- 1 root root 8192 Mar 25 21:40 principal
-rw------- 1 root root 8192 Mar 25 21:40 principal.kadm5
-rw------- 1 root root    0 Mar 25 21:40 principal.kadm5.lock
-rw------- 1 root root    0 Mar 25 21:40 principal.ok

2.2.6 创建 Kerberos 管理员账号

# 这里会提示时输入管理员的密码,再次确认,未报错则创建成功。
[root@cdh1 software]# /usr/sbin/kadmin.local -q "addprinc admin/[email protected]"
Authenticating as principal root/[email protected] with password.
WARNING: no policy specified for admin/[email protected]; defaulting to no policy
Enter password for principal "admin/[email protected]":
Re-enter password for principal "admin/[email protected]":
Principal "admin/[email protected]" created.

2.2.7 将 Kerberos 添加到自启动服务,并启动krb5kdc和kadmin服务

systemctl enable krb5kdc
systemctl enable kadmin

systemctl start krb5kdc
systemctl start kadmin

2.2.8 测试

# 1 提示输入密码时,输入 admin 的密码(Kerberos 管理员账号的密码)
[root@cdh1 software]# kinit admin/[email protected]
Password for admin/[email protected]:

# 2 查看所有的 Principal
/usr/sbin/kadmin.local -q "listprincs"

# klist
[root@cdh1 software]# klist
Ticket cache: FILE:/tmp/krb5cc_0
Default principal: admin/[email protected]
Valid starting       Expires              Service principal
03/25/2020 22:05:36  03/26/2020 22:05:36  krbtgt/[email protected]

2.3 应用服务节点的安装

# 1 通 KDC 节点安装类似,这里只需要安装如下两个服务(所有客户端的节点都需要安装)
# 或者直接 yum 安装:yum -y install krb5-libs krb5-workstation
rpm -ivh krb5-libs-1.15.1-37.el7_7.2.x86_64.rpm
rpm -ivh libkadm5-1.15.1-37.el7_7.2.x86_64.rpm
rpm -ivh krb5-workstation-1.15.1-37.el7_7.2.x86_64.rpm

# 2 如果是 CDH ,还需要在 Cloudera Manager Server服务器上安装额外的包
#  OpenLDAP 是 LDAP 的开源套件应用程序开发工具, LDAP是一组用于通过Internet访问目录服务的协议,
#  类似于DNS信息在Internet上传播的方式。openldap-clients软件包包含访问和修改OpenLDAP目录所需的客户端程序。
#
#  也可以直接通过 yum 方式安装:yum -y install openldap-clients
wget http://mirror.centos.org/centos/7/os/x86_64/Packages/openldap-clients-2.4.44-21.el7_6.x86_64.rpm
# 后面我会专门发一篇文章来介绍 LDAP 的安装和使用
rpm -ivh openldap-clients-2.4.44-21.el7_6.x86_64.rpm

# 3 将 KDC 服务节点的 /etc/krb5.conf 拷贝到所有Kerberos客户端
scp /etc/krb5.conf root@cdh2:/etc/
scp /etc/krb5.conf root@cdh3:/etc/

2.4 客户端节点上的使用和配置

进行这一部分配置可以先跳到 3 与CDH 集成 。如果外部某个节点需要访问 Kerberos 应用服务端节点上的某个服务(例如Hive),这里就需要对客户端节点进行一些配置。下面以 Beeline 连接 Hive 为例(Beeline的详细介绍请查看第六部分的内容)。

首先需要客户端获取认证的票据,这就需要我们按照应用服务端安装的步骤安装并配置好 Kerberos 的环境,环境配置完毕后,需要通过 kinit 获取 KDC 处认证授权(TGS)的票据,这个票据就缓存在客户端节点,带有一个生命周期,在生命周期内可以访问正常请求Kerberos的应用服务节点。

# kinit 获取一个7天有效期的认证:
# 根据第三部分的命令,创建一个 hive/[email protected] 的主体名
kinit -l 7d -kt /etc/hive/conf/hive.keytab  hive/[email protected]

kinit 指定 lifetime

因为我们使用的工具是 Beeline,Beeline 为 Hive 的新 CLI,因此这里需要对 Hive 的配置文件进行配置修改 /etc/hive/conf.cloudera.hive/core-site.xml 文件中添加或修改配置如下(说明可以查看官方文档Hadoop in Secure Mode),而 /etc/hive/conf/core-site.xml配置文件不用修改(值默认为 simple )。

<property>
  <name>hadoop.security.authentication</name>
  <!--<value>simple</value>-->
  <value>kerberos</value>
</property>

添加或修改/etc/hive/conf.cloudera.hive/hive-site.xml配置文件:

<property>
  <name>hive.metastore.kerberos.keytab.file</name>
  <value>/etc/hive/conf/hive.keytab</value>
</property>
<property>
  <name>hive.server2.authentication.kerberos.keytab</name>
  <value>/etc/hive/conf/hive.keytab</value>
</property>

<property>
  <name>hive.metastore.kerberos.principal</name>
  <value>hive/[email protected]</value>
</property>
<property>
  <name>hive.server2.authentication.kerberos.principal</name>
  <value>hive/[email protected]</value>
</property>

<property>
  <name>hive.metastore.sasl.enabled</name>
  <value>true</value>
</property>
<property>
  <name>hive.server2.authentication</name>
  <value>kerberos</value>
</property>


3 与CDH 集成

以CDH 为例,如果CDH 已安装了 Sentry,先停止 Sentry,等安装完 Kerberos 之后再把这个服务开启。

# 1 在KDC中给Cloudera Manager添加管理员账号。
#  依然会要求我们设置新创建的账号的密码
[root@cdh1 software]# /usr/sbin/kadmin.local -q "addprinc cloudera-scm/[email protected]"
Authenticating as principal admin/[email protected] with password.
WARNING: no policy specified for cloudera-scm/[email protected]; defaulting to no policy
Enter password for principal "cloudera-scm/[email protected]":
Re-enter password for principal "cloudera-scm/[email protected]":
Principal "cloudera-scm/[email protected]" created.

# 2 进入Cloudera Manager的“管理”->“安全”界面
# ①选择“启用Kerberos”
# ②确保列出的所有检查项都已完成,然后全部点击勾选
# ③点击“继续”,配置相关的KDC信息,包括类型、KDC服务器、KDC Realm、加密类型以及待创建的Service Principal(hdfs,yarn,,hbase,hive等)的更新生命期等
# ④不建议让Cloudera Manager来管理krb5.conf(不勾选), 点击“继续”
# ⑤输入Cloudera Manager的 Kerbers 管理员账号,一定得和之前创建的账号一致,点击“继续”
# ⑥点击“继续”启用Kerberos
# ⑦Kerberos启用完成,点击“继续”
# ⑧勾选重启集群,点击“继续”
# ⑨集群重启完成,点击“继续”
# ⑩点击“继续”
# ⑪点击“完成”,至此已成功启用Kerberos。
# ⑫回到主页,一切正常,再次查看“管理”->“安全”,界面显示“已成功启用 Kerberos。”


# 3 以 hiveuser01 来操作 Hive
## 3.1 创建 hiveuser01 的 principal。(hiveuser01)
/usr/sbin/kadmin.local -q "addprinc [email protected]"

## 3.2 使用 hiveuser01 登陆 Kerberos
kdestroy
kinit hiveuser01
klist

## 3.3 为 hiveuser01 生成一个 keytab 文件
##  [email protected] 必须为已存在的 Principal
##  也可以使用 kadmin 来生成。
/usr/sbin/kadmin.local -q "xst -k ./hive_user.keytab [email protected]"

## 3.4 通过 keytab 文件认证用户
kinit -kt ./hive_user.keytab [email protected]

## 3.5 更新 ticket
##  如果无法更新,是因为 [email protected] 的 renewlife 被设置成了0
##  可以通过这个命令查看(kadmin.local下执行): getprinc [email protected]
##  modprinc -maxrenewlife "1 week" +allow_renewable [email protected]
kinit -R

4 Beeline 执行Hive sql 脚本

Beeline 的详细使用可以查看我的另一篇blog 《Beeline 的进阶使用》。例如本地环境配置完毕之后,可以远程提交 SQL,执行 sql 脚本文件

# 1 执行单个脚本
# 参数说明:
#  -n	username,连接 Hive 的用户名(如果未开启权限认证可以不写)
#  -p   password, 连接 Hive 的用户的密码(如果未开启权限认证可以不写)
#  -d   driver class, 连接 Hive 的 驱动类(无特殊情况下,可以选填)
#  -u   database url, 必填,连接 Hive 的 URL
#  --hiveconf  格式为 property=value , 设置 Hive 属性值
#  --hivevar  格式为 name=value,配置会话级别的变量名和值,例如 --hivevar hive.security.authorization.enabled=false
#  -e   query, 执行的 查询语句
#  --help  查看帮助
#  -f   执行的脚本文件
beeline -n hive -p hive -d "org.apache.hive.jdbc.HiveDriver" -u "jdbc:hive2://cdh3:10000/default;principal=hive/[email protected]" \
--hiveconf mapreduce.job.queuename=datacenter \
-f ./my-hive.sql


# 2 批量执行多个脚本
# 我们通过前面可以看到,不管是 sql 语句的执行,还是 sql 脚本的执行,都是在前台执行,
# 如果有多个 beeline 命令要执行,则需要前面先执行后面的等待执行,这样很不适合于脚本的自动化和批量处理。
# 
# 此时我们可以通过 ,在 CentOS 环境下我们可以使用 nohup 命令从终端断开进行后台处理。
# 如下所示执行了两个后台命令,这样会在后台启动一个进程执行脚本或 SQL ,并将执行的结果和日志重定向输出到指定文件中。
# 
# 如下面所示,直接提交两个 sql 脚本,并将执行的日志重定向到日志文件中。这样就可以同时提交多个脚本文件。
nohup beeline -n hive -p hive -d "org.apache.hive.jdbc.HiveDriver" -u "jdbc:hive2://cdh3:10000/default;principal=hive/[email protected]" \
--hiveconf mapreduce.job.queuename=datacenter --silent=true --showHeader=true --outputformat=csv2 \
-f ./my-hive00.sql  \
</dev/null >> /tmp/output.log 2>> /tmp/error.log &

nohup beeline -n hive -p hive -d "org.apache.hive.jdbc.HiveDriver" -u "jdbc:hive2://cdh3:10000/default;principal=hive/[email protected]" \
--hiveconf mapreduce.job.queuename=datacenter --silent=true --showHeader=true --outputformat=dsv \
-f ./my-hive01.sql \
</dev/null >> /tmp/output.log 2>> /tmp/error.log &

5 DataX 离线同步数据到Kerberos认证的 HDFS

DataX 是一个解压即可使用的工具,更详细的介绍可以查看我的另一篇blog 《DataX离线数据同步》。这里介绍如何使用 DataX 离线远程将数据同步到带有 Kerberos 认证的HDFS 上。

在 CDH 环境默认 HDFS 的 NameNode 的端口 8020。数据迁移部分实质就是将不同数据源的数据写入到 HDFS 上, 例如 hdfs://${fs.defaultFS}:8020/${yourPath},因此需要申请能够访问 8020 端口的权限,主要用来写入数据。如果DataNode开启了 SASL,则还需要开启1004端口(dfs.datanode.address配置项可以获知)。

假如现在数据源为 ODPS ,需要定时将数据写入 HDFS ,但是 HDFS 是在另外一个集群且网络是隔离的,此时 ODPS 相对于 HDFS 就类似与域外的访问。在 ODPS 所处的环境下有一个调度系统,调度系统的某个 Worker 申请了权限可以成功对接访问 HDFS,HDFS 集群开启了SASL和 Kerberos访问认证。

对于这种情况 DataX 也可以成功实现数据的传输离线同步,需要配置上 Kerberos 的参数,这里重点是对于这种域外访问,直接写入数据时,数据会写入到远程的 DataNode 节点,但是这个节点的 ip 是一个集群内网的ip,这样在连接访问DataNode 时就会超时异常,如下图,写入数据时会报6000 mills timeout while waiting for channel to be ready for connect. ch:java.nio.channels.SocketChannel[connection-pending remote=xxx.xxx.xxx.xxx:1004] 而remote连接的那个ip正式 Hadoop 内网集群的ip,对于这种需要指定如下的参数(在hdfs-site.xml),如果是程序中,可以通过这种方式设定 Configuration conf=new Configuration(); conf.set("dfs.client.use.datanode.hostname", "true");。
DataX 报错

<property>
    <name>dfs.client.use.datanode.hostname</name>
    <value>true</value>
    <description>only cofig in clients</description>
</property>

对于DataX 只需要在 hadoopConfig 中添加Hadoop的相关的配置参数 "dfs.client.use.datanode.hostname": true,完整的配置如下:

{
  "job": {
    "setting": {
      "speed": {
        "channel": 1
      }
    },
    "content": [
      {
        "reader": {
          "name": "odpsreader",
          "parameter": {
            "accessId": "3o************DZ",
            "accessKey": "Myk************************Tly",
            "odpsServer": "http://xx.x.xxx.xxx/api",
            "tunnelServer": "http://xx.x.xxx.xxx",
            "project": "targetProjectName",
            "table": "tableName",
            "column": [
              "customer_id",
              "nickname"
            ]
          }
        },
        "writer": {
          "name": "hdfswriter",
          "parameter": {
            "defaultFS": "hdfs://xx.x.xxx.xxx:8020",
            "path": "/user/hive/warehouse/xxx.db/xxx_tb",
            "fileType": "orc",
            "compress": "NONE",
            "fieldDelimiter": "|",
            "fileName": "xxx",
            "column": [
              {
                "name": "col1",
                "type": "BIGINT"
              },
              {
                "name": "col2",
                "type": "STRING"
              },
              {
                "name": "col3",
                "type": "TIMESTAMP"
              },
              {
                "name": "col4",
                "type": "date"
              }
            ],
            "haveKerberos": true,
            "kerberosKeytabFilePath": "/xxx/xxxx/xxx.keytab",
            "kerberosPrincipal": "hive/[email protected]",
            "hadoopConfig": {
              "dfs.http.policy": "HTTPS_ONLY",
              "dfs.data.transfer.protection": "integrity",
              "dfs.client.use.datanode.hostname": true,
              "dfs.datanode.address": "x.x.x.x:1004"
            },
            "writeMode": "append"
          }
        }
      }
    ]
  }
}

注意

  • 在上面的json 中的hdfswriter,如果 fileTypetext,则compress 支持的格式有gzipbzip2或者不配置。
  • fileTypetext时只能使用单字符,虽然使用一些特殊字符(例如:),虽然 DataX 并不会报错,并且在Hive创建表时也不会报错,但是Hive是无法识别这个字段分割符的,查询的总记录数是没问题的,但是字段的值都为 NULL。
  • fileTypeorc时,需要配置上compress ,值可以为NONESNAPPY,在这里我们可以使用一些特殊字符作为字段分隔符(例如:),这时创建表的时候加上ROW FORMAT DELIMITED FIELDS TERMINATED BY '║' STORED AS ORC,我们就可以正常的查询数据。这个也是比较推荐的一种配置方式,可以很有效的避免分隔符导致的字段值不是逾期的异常问题。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章