Audit logs

审计日志可以追踪对 OpenSearch 集群的访问,既适用于合规需求,也能在安全事件发生后帮助调查。你可以配置要记录的事件类别、日志消息的详细程度,以及日志存储位置。

OpenSearch 支持两种审计日志模式:

模式 要求 配置位置
标准模式(默认) 启用细粒度访问控制(FGAC)的 Security 插件。 安全索引中的 audit.yml 文件,以及 REST API。
独立模式 不使用 FGAC。以仅 SSL 模式(plugins.security.ssl_only: true)或禁用安全功能模式(plugins.security.disabled: true)运行。 opensearch.yml 及动态集群设置。

独立模式的更多信息,参阅独立审计日志。

启用审计日志(标准模式)

默认情况下审计日志关闭。启用方法如下:

  1. 在每个节点的 opensearch.yml 中添加:

    plugins.security.audit.type: internal_opensearch
    

    这个设置会把审计日志存到当前集群。其他存储选项见审计日志存储类型。

  2. 重启每个节点。

审计日志需要同时具备两个设置:opensearch.yml 中的存储类型(plugins.security.audit.type),以及 audit.yml 中的 config.enabled: true。Security 插件提供的 audit.yml 默认把 config.enabled 设为 true,所以新集群看上去可能已经启用了审计日志。不过,在指定存储类型之前,Security 插件无法为审计日志创建存储端点,也就不会记录任何事件;启动时还会警告没有可用的默认存储。

完成初始设置后,可以在 OpenSearch Dashboards 中管理审计日志类别及其他设置。打开 Security,再选择 Audit logs。也可以在 audit.yml 和 opensearch.yml 中配置审计日志,具体使用哪个文件取决于设置,见后文。还可以通过审计日志 API管理和更新设置。

追踪的事件

审计日志通过 HTTP 请求(REST)及传输层这两种方式记录事件。下表说明各事件,以及它们是否在 REST 层或传输层记录:

事件 REST 传输层 说明
FAILED_LOGIN 是 是 无法验证请求凭据,通常是用户不存在或密码错误。
AUTHENTICATED 是 是 用户成功通过身份验证。
MISSING_PRIVILEGES 否 是 用户缺少发起请求所需的权限。
GRANTED_PRIVILEGES 否 是 用户成功向 OpenSearch 发起请求。
SSL_EXCEPTION 是 是 有人尝试在没有有效 SSL/TLS 证书的情况下访问 OpenSearch。
opensearch_SECURITY_INDEX_ATTEMPT 否 是 有人尝试在缺少所需权限或 TLS 管理员证书的情况下,修改 Security 插件的内部用户和权限索引。
BAD_HEADERS 是 是 有人尝试利用 Security 插件的内部标头伪造发往 OpenSearch 的请求。
CLUSTER_SETTINGS_CHANGED 否 是 持久或临时集群设置发生变化。默认关闭。
INDEX_SETTINGS_CHANGED 否 是 索引设置发生变化。默认关闭。
REQUEST_AUDIT 是 是 收到并处理了 REST 请求。仅在独立审计日志模式中生成。如何抑制该事件,见抑制 REQUEST_AUDIT 事件。
TRANSPORT_AUDIT 否 是 节点收到传输层请求。仅在独立审计日志模式中生成。
RESOURCE_ACCESS_GRANTED 否 是 授予了对共享资源的访问。默认关闭。
RESOURCE_ACCESS_DENIED 否 是 拒绝了对共享资源的访问。默认关闭。
RESOURCE_SHARING_CHANGED 否 是 资源共享配置发生变化。默认关闭。

REQUEST_AUDIT 源于 REST 请求(audit_request_origin: REST),但事件本身以 audit_request_layer: TRANSPORT 记录。因此,disabled_categories、disabled_transport_categories 或 disabled_rest_categories 中任意一个都能抑制该事件:把 REQUEST_AUDIT 加入其中任意一项即可。

审计日志设置

下面的默认日志设置适用于大多数场景。你也可以调整设置,以节省存储空间,或使记录的信息更符合实际需求。

audit.yml 中的设置

本节的设置存储在 audit.yml 文件中。

排除事件类别

要排除类别,在以下设置中列出:

config:
  audit:
    disabled_rest_categories: <disabled categories>
    disabled_transport_categories: <disabled categories>

例如:

config:
  audit:
    disabled_rest_categories:
      - AUTHENTICATED
      - GRANTED_PRIVILEGES
    disabled_transport_categories: [ GRANTED_PRIVILEGES ]

也可以使用统一的 disabled_categories 设置,一次关闭两个层上的类别:

config:
  audit:
    disabled_categories:
      - AUTHENTICATED
      - GRANTED_PRIVILEGES

当 disabled_categories 与 disabled_rest_categories 或 disabled_transport_categories 同时配置时,只要某个类别出现在统一设置或该层专用设置中的任意一项,它就会在对应层被关闭。

同时使用统一设置和分层设置时,会记录弃用警告,建议迁移为仅使用 disabled_categories。

例如,以下配置用 disabled_categories 在两个层都关闭 AUTHENTICATED,同时只在 REST 层关闭 SSL_EXCEPTION:

config:
  audit:
    disabled_categories:
      - AUTHENTICATED
    disabled_rest_categories:
      - SSL_EXCEPTION

默认情况下,传输层不记录 CLUSTER_SETTINGS_CHANGED 和 INDEX_SETTINGS_CHANGED。要开启这两类事件,从 disabled_transport_categories 中移除它们:

config:
  audit:
    disabled_transport_categories:
      - AUTHENTICATED
      - GRANTED_PRIVILEGES

如果想记录所有类别的事件,使用 NONE:

config:
  audit:
    disabled_rest_categories: NONE
    disabled_transport_categories: NONE

关闭 REST 层或传输层

默认情况下,Security 插件会记录 REST 层和传输层的事件。可以关闭其中一种:

config:
  audit:
    enable_rest: false
    enable_transport: false

关闭请求正文记录

默认情况下,Security 插件会为 REST 层及传输层记录请求正文(如果存在)。如果不想或不需要记录正文,可以关闭:

config:
  audit:
    log_request_body: false

记录索引名称

默认情况下,Security 插件会记录请求影响的所有索引。索引名称可能是别名,也可能包含通配符或日期模式,因此插件既记录用户提交的索引名,也记录解析后的实际索引名。

例如,使用别名或通配符时,审计事件可能如下:

audit_trace_indices: [
  "human*"
],
audit_trace_resolved_indices: [
  "humanresources"
]

可以用以下设置关闭这一功能:

config:
  audit:
    resolve_indices: false

只有同时将 config.audit.log_request_body 设为 false 时,这项功能才会关闭。

配置 bulk 请求处理

bulk 请求可能包含许多索引操作。默认情况下,Security 插件只记录整个 bulk 请求,而不记录每个单独操作。

可以配置插件,把每个索引操作记录为一个独立事件:

config:
  audit:
    resolve_bulk_requests: true

这一变化可能在审计日志中生成极多事件。因此,如果经常使用 _bulk API,原文不建议开启这个设置。

排除请求

要让某些请求不被记录,可以配置传输层请求的 action、HTTP 请求路径(REST),或者同时配置两者:

config:
  audit:
    ignore_requests: ["indices:data/read/*", "SearchRequest"]

排除用户

默认情况下,Security 插件记录所有用户的事件,但会排除 OpenSearch Dashboards 内部服务器用户 kibanaserver。你也可以排除其他用户:

config:
  audit:
    ignore_users:
      - kibanaserver
      - admin

要记录所有用户的请求,使用 NONE:

config:
  audit:
    ignore_users: NONE

排除敏感标头

可以让敏感标头不进入日志,例如 Authorization: 标头:

config:
  audit:
    exclude_sensitive_headers: true

opensearch.yml 中的设置

本节设置存储在 opensearch.yml 中。它们在运行时如何应用,取决于审计日志模式:

  • 在独立模式(仅 SSL 或禁用安全功能)下,大多数审计过滤与合规设置都能通过集群设置 API在运行时修改,不需要重启节点。包括 log_request_body、resolve_indices、disabled_categories、enable_rest、enable_transport、ignore_users 和 ignore_requests。
  • 在启用 FGAC 的标准模式下,审计配置存储在 audit.yml 中,对应的 plugins.security.audit.config.* 和 plugins.security.audit.compliance.* 集群设置不会更新它。PUT _cluster/settings 请求可能成功,却没有改变审计配置。body_logging_exclusions 是例外:FGAC 模式下也能通过集群设置 API 更新它。

某些审计设置是静态的,修改后必须重启节点:action_groups.<NAME>、log4j.enable_mdc_routing、config.index、线程池设置,以及日志接收端连接设置。

启用 FGAC 时,更新动态审计设置需要使用 plugins.security.restapi.roles_enabled 中列出的角色。仅 SSL 或禁用安全功能模式下不执行这一限制。body_logging_exclusions 可以在不具备该提升角色的情况下更新。

各模式下,调用者通过 GET _cluster/settings 能读取的审计设置如下:

模式 设置响应中可见的审计设置
独立模式,仅 SSL 任何调用者都能读取不含秘密的动态审计配置(plugins.security.audit.config.* 和 plugins.security.audit.compliance.*)。含凭据的日志接收端设置仍会隐藏。
独立模式,禁用安全功能 不对 plugins.security.audit.* 设置进行过滤,因此日志接收端凭据和 PEM 内容可能可见。
FGAC 对所有调用者过滤整个 plugins.security.audit.* 子树。这项过滤不基于角色。

plugins.security.audit.enabled 运行时开关只适用于独立审计日志。操作方法见独立审计日志。

排除事件类别

可以在 opensearch.yml 中使用 plugins.security.audit.config 前缀配置关闭的类别。这适用于非 FGAC 模式(仅 SSL 或禁用安全功能),因为这些模式无法使用存储 audit.yml 的安全索引:

plugins.security.audit.config.disabled_categories:
  - AUTHENTICATED
  - GRANTED_PRIVILEGES

分层设置 disabled_rest_categories 和 disabled_transport_categories 已弃用,应该使用统一的 disabled_categories。

分层设置仍然可用:

plugins.security.audit.config.disabled_rest_categories:
  - AUTHENTICATED
  - GRANTED_PRIVILEGES
plugins.security.audit.config.disabled_transport_categories:
  - AUTHENTICATED
  - GRANTED_PRIVILEGES

统一设置和分层设置同时配置时,只要类别出现在任意一项,它就会在相应层关闭。系统也会记录弃用警告,建议仅使用 disabled_categories。

disabled_categories 只抑制 REST 和传输层类别,不影响 COMPLIANCE_* 类别。后者仅受合规设置控制,包括 compliance.enabled、监视的索引与字段,以及合规配置中的忽略用户设置。

排除特定请求正文

body_logging_exclusions 可以针对特定 action 或 REST 路径省略请求正文,同时继续记录其他请求的正文。log_request_body 作用于每一个请求,无法选择性地排除批量写入等高吞吐操作。

展开后的 action group 模式与直接指定的排除模式,共同构成一个通配符匹配器。每个审计层使用下表对应的标识进行匹配。一旦匹配成功,审计事件中就会省略请求正文字段,用户、IP 地址、索引、时间戳等其他字段仍然保留。

标识 说明 匹配对象
传输层 action 内部 action 名称,例如 indices:data/write/bulk[s][p]。 传输层审计事件。
REST 路径 HTTP 请求路径,例如 /_bulk。REST 路径始终以 / 开头。 REST 层审计事件。

两种标识都支持用 * 表示通配符。例如,indices:data/write/bulk* 能匹配 indices:data/write/bulk[s][p]。

配置 action group

action group 是有名称的 action 模式、REST 路径或两者的集合,在 opensearch.yml 中静态定义。名称由你选择,可以使用对运维有意义的名称:

plugins.security.audit.config.action_groups.BULK: "indices:data/write/bulk*,/_bulk"
plugins.security.audit.config.action_groups.SEARCH: "indices:data/read/search*,/_search"
plugins.security.audit.config.action_groups.INDEX_ADMIN: "indices:admin/*"

每个 action group 把一个名称映射到以逗号分隔的字面值或通配符模式列表,例如 indices:data/write/bulk*、/_bulk 或 indices:data/write/*。所有模式使用同一个匹配器;:、/ 和 * 等字符不会把模式指定给某个审计层。

action group 属于静态设置,修改后需要重启节点。group 名称区分大小写。

配置正文排除规则

body_logging_exclusions 引用 action group 名称或直接指定的模式。在 opensearch.yml 中设置初始排除项:

plugins.security.audit.config.body_logging_exclusions:
  - BULK

这个设置是动态的,所以也可以在运行时更新,而不重启集群:

PUT _cluster/settings
{
  "persistent": {
    "plugins.security.audit.config.body_logging_exclusions": ["BULK", "SEARCH"]
  }
}

列表中的每一项按如下方式处理:

  1. 如果该项匹配已定义的 action group 名称,就展开该 group 的模式。
  2. 如果没有匹配任何 group 名称,则把该项视为直接指定的模式,可以是字面值或通配符。

对没有匹配 group 名称的条目,如果既不包含 :、也不以 / 开头、又不包含 *,就会记录警告,因为它不太可能匹配 action 或 REST 路径。这里检查的是开头的 /,而不是字符串任意位置是否存在 /:例如 _bulk/items 虽然包含斜杠,却不是以斜杠开头,仍会触发警告。此检查只决定是否记录警告,该项仍会进入统一匹配器。

bulk 请求

配置 resolve_bulk_requests: true,记录每个 bulk 子项时,排除检查使用的是父 bulk action 字符串。因此,排除 BULK group 会省略同一 bulk 请求中所有子项(index、update、delete)的正文。无法在同一个 bulk 请求中保留 index 子项正文而仅丢弃 delete 子项正文。

与 log_request_body 的关系

正文排除规则只在 log_request_body 为 true 时生效。如果它为 false,无论排除规则如何配置,都不会记录任何请求正文。

配置示例

下面定义三个 action group,并排除 bulk 请求的正文:

# opensearch.yml

# Define action groups (static, requires restart)
plugins.security.audit.config.action_groups.BULK: "indices:data/write/bulk*,/_bulk"
plugins.security.audit.config.action_groups.SEARCH: "indices:data/read/search*,/_search"
plugins.security.audit.config.action_groups.MONITORING: "cluster:monitor/*,indices:monitor/*"

# Initial exclusions (can be updated at runtime using _cluster/settings)
plugins.security.audit.config.body_logging_exclusions:
  - BULK

使用该配置时,不同请求类型的正文记录情况如下:

请求类型 是否记录正文
bulk 写入 否,因为排除了 BULK group。
搜索 是。
创建索引 是。
监控 是,除非把 MONITORING 加入排除项。

要在运行时增加搜索正文排除项,发送:

PUT _cluster/settings
{
  "persistent": {
    "plugins.security.audit.config.body_logging_exclusions": ["BULK", "SEARCH"]
  }
}

要清空所有排除项,恢复记录全部正文:

PUT _cluster/settings
{
  "persistent": {
    "plugins.security.audit.config.body_logging_exclusions": []
  }
}

Log4j MDC 路由

使用 log4j 审计日志接收端时,可以启用映射诊断上下文(Mapped Diagnostic Context,MDC)路由,让 Log4j 按事件属性把审计事件分配给不同的 appender:

plugins.security.audit.config.log4j.enable_mdc_routing: true

启用后,每个审计事件会设置以下 MDC 键:

  • audit_category:审计事件类别,例如 REQUEST_AUDIT 或 GRANTED_PRIVILEGES。
  • audit_action:action 名称。
  • audit_user:实际生效的用户。
  • audit_request_type:请求类型。

在 log4j2.properties 中使用 Log4j routing appender,即可按类别、用户或其他 MDC 键拆分审计日志。这是静态设置,需要重启节点。

配置审计日志索引名称

默认情况下,Security 插件把审计事件存储到每日滚动的索引中,名称为 security-auditlog-YYYY.MM.dd。可以设置索引名称:

plugins.security.audit.config.index: myauditlogindex

在索引名中使用日期模式,可以按日、周或月滚动:

plugins.security.audit.config.index: "'auditlog-'YYYY.MM.dd"

日期模式格式参考 Joda DateTimeFormat 文档。

进阶:调整线程池

插件异步记录事件,以尽量减少对集群性能的影响。它使用固定线程池记录事件:

plugins.security.audit.config.threadpool.size: <integer>

默认值为 10。设为 0 会关闭线程池,改为同步记录。可以设置每个线程的最大队列长度:

plugins.security.audit.config.threadpool.max_queue_len: 100000

关闭审计日志

要关闭已启用的审计日志,可以从 opensearch.yml 中移除 plugins.security.audit.type: internal_opensearch,或者在 OpenSearch Dashboards 中取消 Enable audit logging 复选框。通过集群设置 API 设置的 plugins.security.audit.enabled 运行时开关,只适用于独立审计日志模式;详见独立审计日志。

审计用户账户与权限配置变更

要记录安全索引的变更,例如角色映射修改、角色创建或删除,在审计日志配置的 compliance: 部分使用以下设置:

_meta:
  type: "audit"
  config_version: 2

config:
  # enable/disable audit logging
  enabled: true

  ...


  compliance:
    # enable/disable compliance
    enabled: true

    # Log updates to internal security changes
    internal_config: true

    # Log only metadata of the document for write events
    write_metadata_only: false

    # Log only diffs for document updates
    write_log_diffs: true

    # List of indices to watch for write events. Wildcard patterns are supported
    # write_watched_indices: ["twitter", "logs-*"]
    write_watched_indices: [".opendistro_security"]

来源:Audit logs | OpenSearch Documentation。原文作者:OpenSearch contributors。许可:Apache-2.0。中文内容和版式作了调整。

Copyright OpenSearch contributors.

Apache-2.0 许可全文
                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright [yyyy] [name of copyright owner]

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容