
# 配置Spark安全审计功能
#### 配置场景
为了确保Spark作业的全面审计，将spark-sql、spark-beeline、spark-submit共三种提交作业的入口进行审计。其中spark-sql和spark-beeline需要记录用户名、IP、以及SQL查询内容；spark-submit需要额外记录提交的Jar包。
对于无法审计的作业提交方式，如Spark-Shell、PySpark和SparkR，将进行禁用。同时，为了提高安全性，将禁用不安全的local运行模式。
审计日志功能的开关应由服务端控制，客户端无法关闭，以防止恶意逃过审计。
本功能配合"MetaStore拦截低版本客户端请求"使用，可以实现对集群中所有Spark作业的强制审计。对于一些难以审计的场景，可以通过服务端参数进行禁用。
#### 约束与限制
- 本章节仅适用于MRS 3.6.0-LTS.1及之后版本。
- Spark审计功能对目录有明确的权限要求： **spark.audit.log.dir** 和**spark.submit.jar.dir**允许自定义路径，但在目录创建时需要注意赋予相应的权限（参考SparkJobHistory目录），必须允许其他用户写入日志，否则会导致任务执行失败。
  
- Spark审计日志清理周期不支持较短的时间： 日志清理功能依赖JobHistory后台定时任务，默认调度周期为1天，如果设置小于1天的时间，会导致文件清理功能异常。
  
- Spark审计日志只能记录启动任务的MRS用户信息，无法审计链路中的其他代理用户： Spark作业从提交到运行中间可能经历多个平台的转发，最终在MRS集群中执行。对于存在代理用户的场景，比如spark-beeline，日志只能记录启动任务的内置MRS用户"spark2x"。对于存在多层代理的场景，比如从DataArts中下发的任务，日志同样只能记录最终启动任务的MRS用户信息，无法记录DataArts平台中的用户信息。对于多人共用MRS用户的情况，日志中同样无法分辨。因此，需要在发放MRS用户时，避免上述类似情况，才能实现精准审计的目标。
  
- Spark-submit Jar包审计功能，存在性能损失，且Jar包会占用较大存储空间：
  - Jar包审计会在spark-submit开始运行前，需要将提交的jar包拷贝至指定目录下，需要消耗一定的时间。
  
  - Jar包审计目录会将集群中所有用户提交的jar包全部备份，会占用较大存储空间，存在较大占满磁盘空间的风险。首先，需要根据集群负载提前预留充足的HDFS空间。其次，清理周期建议设置为2\~3天，并定期转储至其它集群单独归档。最后，由于大部分用户会经常提交同名jar包，jar包审计目录下会存在较多重复内容，建议转储前先压缩。
   
 
#### 操作步骤
为避免用户修改Spark配置参数，关闭审计日志功能。在服务端预设了一个公共配置文件"hdfs://hacluster/user/spark/common/spark-common-defaults.conf"，使所有提交到本集群运行的Spark作业均使用该文件中的参数。
1. 使用root用户登录客户端节点，加载客户端环境变量： 
   **source** *客户端安装路径* **/bigdata_env**
   安全集群需要进行认证：
   **kinit** *具备HDFS管理员权限的用户名*
   *输入用户名密码*
   
   
2. 创建公共配置文件，开启审计日志、Jar包备份等开关。 
   1. 在本地创建"spark-common-defaults.conf"文件。
   
   2. 在其中添加审计日志、Jar包审计、提交方式禁用等开关的配置参数，如下所示：
      ```
      spark.audit.log.enabled=true
      spark.audit.log.dir=hdfs://hacluster/sparkJobHistory/Audit
      spark.submit.jar.backup.enabled=true
      spark.submit.jar.dir=hdfs://hacluster/sparkJobHistory/Submit
      spark.forbid.local.mode=true
      spark.forbid.spark.shell=true
      spark.forbid.sparkR=true
      spark.forbid.pyspark=true
      ```
      
   
   
   
   
3. 将公共配置文件上传至预设路径。 
   1. 创建common目录： **hdfs dfs -mkdir hdfs://hacluster/user/spark/common/**
      
   
   2. 修改common目录属主： **hdfs dfs -chown spark:hadoop hdfs://hacluster/user/spark/common/**
      
   
   3. 修改common目录权限： **hdfs dfs -chmod 1777 hdfs://hacluster/user/spark/common/**
      
   
   4. 参考如下命令上传文件： **hdfs dfs -put spark-common-defaults.conf hdfs://hacluster/user/spark/common/**
      
   
   5. 修改**spark-common-defaults.conf** 文件属主，避免被无权限用户修改：
      **hdfs dfs -chown admin:supergroup hdfs://hacluster/user/spark/common/spark-common-defaults.conf**
      
   
   6. 修改**spark-common-defaults.conf** 文件权限：
      **hdfs dfs -chmod 644 hdfs://hacluster/user/spark/common/spark-common-defaults.conf**
      
   
   
   
   
4. 创建审计日志目录、Jar包归档目录。 
   1. 创建spark-sql、spark-beeline审计日志目录： **hdfs dfs -mkdir hdfs://hacluster/sparkJobHistory/Audit**
      
   
   2. 修改spark-sql、spark-beeline审计日志目录属主： **hdfs dfs -chown spark:hadoop hdfs://hacluster/sparkJobHistory/Audit**
      
   
   3. 修改spark-sql、spark-beeline审计日志目录权限： **hdfs dfs -chmod 1777 hdfs://hacluster/sparkJobHistory/Audit**
      
   
   4. 创建spark-submit Jar包备份目录： **hdfs dfs -mkdir hdfs://hacluster/sparkJobHistory/Submit**
      
   
   5. 修改spark-submit Jar包备份目录属主： **hdfs dfs -chown spark:hadoop hdfs://hacluster/sparkJobHistory/Submit**
      
   
   6. 修改spark-submit Jar包备份目录权限： **hdfs dfs -chmod 1777 hdfs://hacluster/sparkJobHistory/Submit**
      
   
   
   
   
5. JDBCServer配置审计日志开关。
   
   1. 登录Manager界面，选择"集群 \> 服务 \> Spark \> 配置 \> 全部配置"，在"JDBCServer \> 自定义 \> custom"中，添加以下配置：
      ```
      spark.audit.log.enabled=true
      spark.audit.log.dir=hdfs://hacluster/sparkJobHistory/Audit
      ```
      
   
   2. 保存配置并重启JDBCServer实例。
   
   
   
   
6. 开启定时清理功能。
   
   1. 在"JobHistory \> 自定义 \> custom"中，添加以下配置：
      ```
      spark.audit.log.enabled=true
      spark.audit.log.dir=hdfs://hacluster/sparkJobHistory/Audit
      spark.audit.log.fs.cleaner.maxAge=7d
      spark.submit.jar.backup.enabled=true
      spark.submit.jar.dir=hdfs://hacluster/sparkJobHistory/Submit
      spark.submit.jar.cleaner.maxAge=2d
      ```
      
   
   2. 保存配置并重启JobHistory实例。
   
   
   
   
 
#### 功能回退
1. 使用root用户登录客户端节点，加载客户端环境变量： 
   **source** *客户端安装路径* **/bigdata_env**
   安全集群需要进行认证：
   **kinit** *{具备HDFS管理员权限的用户名} {密码}*
   
   
2. 删除spark-common-defaults.conf文件： 
   **hdfs dfs -rm -r hdfs://hacluster/user/spark/common/spark-common-defaults.conf**
   
   
3. 删除common、Audit、Jar包目录： 
   **hdfs dfs -rm -r hdfs://hacluster/user/spark/common/**
   **hdfs dfs -rm -r hdfs://hacluster/sparkJobHistory/Audit**
   **hdfs dfs -rm -r hdfs://hacluster/sparkJobHistory/Submit**
   
   
4. 删除[5]中JDBCServer新增的自定义参数，保存配置并重启JDBCServer实例。
5. 删除[6]中JobHistory新增的自定义参数，保存配置并重启JobHistory实例。
 
#### 审计日志介绍
- **配置参数**
  
  | 参数名称                              | 参数说明                                              | 参数取值                                                                                                                                                                                                                                                                                                                                |
  |:---|:---|:---|
  | spark.audit.log.enabled           | 审计日志开关，默认不开启。                                     | - true  - false   |
  | spark.audit.log.dir               | 审计日志归档路径，可自定义。                                    | hdfs://hacluster/sparkJobHistory/Audit （示例）                                                                                                                                                                                                                                                                                         |
  | spark.audit.log.fs.cleaner.maxAge | 审计日志目录的清理周期，清理周期不能少于1d，文件先移动到回收站目录中，待到期后彻底从系统中删除。 | 7d （默认值）                                                                                                                                                                                                                                                                                                                            |
     
  
- **审计日志目录**
  如图所示，目录结构为："*自定义路径/用户名* /*日期* /*小时（24小时制）* /*applicationID*/Audit.log"：
  ![](https://support.huaweicloud.com/cmpntguide-lts-mrs/public_sys-resources/note_3.0-zh-cn.png)
  spark.eventLog.compress 控制是否压缩审计日志。若为true，则开启压缩；若为false，则不压缩。
  spark.eventLog.compression.codec 控制日志压缩格式，默认格式为zstd。
  
- **审计日志内容**
  如下表所示，日志内容为：
  
  | 参数名称           | 参数说明                                                            |
  |:---|:---|
  | submitUser     | Spark作业提交时的认证用户名。                                               |
  | submitIP       | Spark作业提交时所在机器的IP。                                              |
  | submitHostName | Spark作业提交时所在机器的Host Name。                                       |
  | submitType     | Spark作业提交时的类型（如果提交时刻无法判断，会暂时赋值为unknown，可根据后续mode值进一步判断作业执行的类型）。 |
  | submitTime     | Spark作业提交时间。                                                    |
  | sparkUser      | Spark作业运行时的认证用户名。                                               |
  | driverIP       | Spark作业运行时Driver所在机器的IP。                                        |
  | driverHostName | Spark作业运行时Driver所在机器的Host Name。                                 |
  | applicationID  | Spark作业的Application ID。                                         |
  | mode           | Spark作业运行时的类型（spark-sql、spark-beeline、spark-submit三种）。          |
  | operation      | Spark作业运行时的操作，如果是SQL类型则显示具体的SQL语句；如果是submit，则显示作业提交的语句。         |
  | isSuccess      | Spark作业是否运行成功。                                                  |
  | startTime      | Spark作业开始运行的时间。                                                 |
  | endTime        | Spark作业结束运行的时间。                                                 |
     
  SQL语句审计日志示意图：
  ![](https://support.huaweicloud.com/cmpntguide-lts-mrs/zh-cn_image_0000002547469113.png "点击放大")
  Submit审计日志示意图：
  ![](https://support.huaweicloud.com/cmpntguide-lts-mrs/zh-cn_image_0000002547389103.png "点击放大")
  
- **日志清理**
  在JobHistory进程中添加自定义参数，配置spark.audit.log.enabled、spark.audit.log.dir、spark.audit.log.fs.cleaner.maxAge，保存重启后方可生效。
  
 
#### Jar包审计介绍
- **配置参数**
  
  | 参数名称                            | 参数说明                                             | 参数取值                                                                                                                                                                                                                                                                                                                                  |
  |:---|:---|:---|
  | spark.submit.jar.backup.enabled | Spark-submit的Jar包审计开关，默认不开启。                     | - true  - false   |
  | spark.submit.jar.dir            | Jar包归档路径，可自定义。                                   | hdfs://hacluster/sparkJobHistory/Submit （示例）                                                                                                                                                                                                                                                                                          |
  | spark.submit.jar.cleaner.maxAge | Jar目录的清理周期，清理周期不能少于1d，文件先移动到回收站目录中，待到期后彻底从系统中删除。 | 2d (预设默认值）                                                                                                                                                                                                                                                                                                                            |
     
  
- **Jar包归档目录**
  目录结构为"*自定义路径/用户名* /*日期* /*小时（24小时制）* /*xxx*.jar"，其中Jar包名在原始基础上，新增了日志与时间字段
  如图中所示，提交运行的Jar包为：spark-examples_2.12-3.3.1-h0.cbu.mrs.350.r11.jar，根据提交用户提交时间的不同，在归档路径中记录了多个Jar包：
  ![](https://support.huaweicloud.com/cmpntguide-lts-mrs/zh-cn_image_0000002515909208.png "点击放大")
  
- **Jar包清理**
  在JobHistory进程中添加自定义参数，配置spark.submit.jar.backup.enabled、spark.submit.jar.dir、spark.submit.jar.cleaner.maxAge，保存重启后方可生效。
  
 
#### 禁用不安全的提交方式
**配置参数** ：
| 参数名称                     | 参数说明                                                                                                                                                                                                                                                                                                                                                                                                                                                                    | 参数取值 |
|:---|:---|:---|
| spark.forbid.local.mode  | 是否禁用local运行模式，默认不开启。 - true：禁用local运行模式  - false：启用local运行模式                          | true |
| spark.forbid.spark.shell | 是否禁用spark-shell提交作业，默认不开启。 - true：禁用spark-shell提交作业  - false：启用spark-shell提交作业   | true |
| spark.forbid.sparkR      | 是否禁用SparkR提交作业，默认不开启。 - true：禁用SparkR提交作业  - false：启用SparkR提交作业                           | true |
| spark.forbid.pyspark     | 是否禁用pyspark提交作业，默认不开启。 - true：禁用pyspark提交作业  - false：启用pyspark提交作业                      | true |
   
#### 常见报错及处理方式
禁用提交方式的报错如下，local模式禁用的判断优先级高于其他提交方式，如果同时配置了多个禁用开关local模式会优先报错：
- spark-shell方式提交作业报错示意图： ![](https://support.huaweicloud.com/cmpntguide-lts-mrs/zh-cn_image_0000002515749294.png "点击放大")
  
- spark local模式运行报错示意图： ![](https://support.huaweicloud.com/cmpntguide-lts-mrs/zh-cn_image_0000002547469115.png "点击放大")
  本功能通常会配合Hive MetaStore拦截低版本客户端请求。
  
- spark-sql被拦截报错示意图，报错信息中会提示客户端与服务端对应版本： ![](https://support.huaweicloud.com/cmpntguide-lts-mrs/zh-cn_image_0000002555182771.png "点击放大")
  
- spark-submit client模式被拦截报错示意图，报错信息中会提示客户端与服务端对应版本： ![](https://support.huaweicloud.com/cmpntguide-lts-mrs/zh-cn_image_0000002524182866.png "点击放大")
  

- spark-submit cluster模式被拦截报错示意图，报错信息会被Yarn截断。可参考Hive MetaStore拦截低版本客户端请求功能，使用最新版本的客户端提交作业： ![](https://support.huaweicloud.com/cmpntguide-lts-mrs/zh-cn_image_0000002524182876.png "点击放大")
  
 
