IAM 服务

前言 这篇文章是阅读 Arch Linux 团队部署、管理、整合身份与访问管理( Identity and Access Management)服务相关代码的笔记,会包含: 如何部署和管理 Keycloak 服务:Ansible 相关 如何管理 Keycloak 上的用户和权限:Terraform 相关 如何将 Web 站点接入通过 Keycloak:OAuth2.0、OIDC、Python、Authlib 相关 如何基于 Keycloak 中的信息,实现权限管理:装饰器和枚举类相关 IAM 服务 有什么用 先说说没有 IAM 服务会有什么问题。 一般团队内会有多种服务,比如:GitLab、Jira、Confluence、MatterMost、Grafana、Kibana、Argo 等,会产生的问题: 每个团队成员入职/离职时,需在每个服务上添加/删除账号 每个团队成员使用服务时,需在每个服务上输入一遍账号密码 每个团队成员需要管理多个服务的密码,如果密码泄漏且相同时,每个服务需要手动修改一遍 IAM 服务的作用: 统一的权限管理。授权服务器可以管理用户对各个应用的访问权限,例如,哪些用户可以访问哪些应用,用户在各个应用中的角色和权限是什么,另外用户账号的增删也只需要一遍。 单点登录。用户只需要在授权服务器上进行一次登录,就可以访问所有连接到该授权服务器的应用。提高用户体验,减少了用户需要记住多个凭证的负担。 降低业务复杂度。授权码流程可以将认证功能分离出业务代码,业务代码只需根据 OAuth2.0、OIDC 获取到的用户信息,更新和管理用户权限相关的用户表,而无需再每个业务内实现2FA、验证码等验证逻辑。 微服务改造的基础。微服务旨在将业务拆分成独立小服务(独立的数据库)从而降低复杂度、提高容错率和扩展性。IAM 在微服务架构中为各个微服务提供了集中、统一的身份验证和权限管理,从而实现安全性,减少重复验证的开销,并提高系统的可维护性和扩展性。 Keycloak 是什么 Keycloak 是 RedHat 开源的身份认证和授权服务实现。通过部署 Keycloak,我们就可以拥有自己的 IAM 服务,Arch Linux 团队的 IAM 服务就是基于 Keycloak。 Keycloak 的部署 Arch Linux 团队的 Keycloak 通过 Ansible 进行部署和管理,相关的 Playbook 和 Role 在这里: ...

七月 9, 2023

备份系统

前言 最近借鉴 Arch Linux 的 infrastructure 仓库中的 Ansible 代码,部署了本地基础设施用的备份系统,本文是对这个过程中的记录和思考。会包含实施前的考量,具体如何实施,以及备份系统本身如何监控。 备份系统 采用什么方案 采用了 borg 作为备份的解决方案。borg 是一个支持去重、压缩、加密的备份程序。 关于加密的意义: 备份系统本质上是将本地的数据拷贝一份存储到其他位置。备份加密指的是将备份的数据,在发送到其他位置前做一次加密,因为备份一般被存储在不可信的第三方,比如 Aliyun、AWS 的对象存储,所以需要加密。 关于去重和压缩的意义: 第三方存储一般是按照使用空间的大小收费的,占用更少的空间意味着更低的成本。 borg 创建备份的时候,会将大文件分为小的分块(chunk),chunk 的大小根据内容动态调整,每个 chunk 有一个哈希值用于去重,哈希值相同的块只存储一份,最后压缩得到的数据大小才是最终的备份大小。 如图所示,Original size 即原始大小 226.77G 的数据,Compressed size 压缩后的大小为 138.41G,Deduplicated size 去重后的大小为 56.10 GB,实际上每月只需支付 56.10 GB 数据的存储费用。 采用什么备份规则 备份是针对整个系统的,第一次是整个系统的全量备份,后续的备份是 borg chunking 机制提供的增量备份。 具体的备份规则见 Arch Linux infrastructure 仓库的 borg-backup.sh.j2 文件 大概的内容如下: 判断需要备份的服务器上是否有数据库类的服务,如果有,基于官方的 dump 工具创建每个数据库的 dump 文件(确保数据库数据的一致性、版本兼容性) 判断 filesystem 是否是 btrfs 如果:服务器根目录是基于 btrfs 文件系统。由于 btrfs 制作快照的时候,子卷的快照是不会包含所有内嵌子卷的内容的,因此: 遍历 / 及其下面所有的子卷 在所有子卷内制作快照。比如:/ 的快照就是 /backup-snapshot,子卷 /home/jinmiaoluo 的快照就是 /home/jinmiaoluo/backup-snapshot 把所有子卷的快照通过 mount -o bind 映射到 /backup 内,比如: 子卷 / 的快照 /backup-snapshot 对应的路径就是 /backup 子卷 /home/jinmiaoluo 的快照 /home/jinmiaoluo/backup-snapshot 对应的路径就是 /backup/home/jinmiaoluo 对 /backup 创建备份,即实现了对整个系统进行备份的目的 否则:服务器根目录不是基于 btrfs 文件系统。直接对 / 创建备份 基于 systemd timer 每天发起 1 次备份操作 需要指出的是:快照可以快速的实现本地的状态留存,就像拍了一张相片一样。但在创建远端的系统备份的时候,则是对整个系统的一次比对和拷贝。好在通过 borg chunking 机制,实际上从第二次开始,会被压缩、加密、发送并存储到远端的内容只是修改的内容,因此,实际的内网带宽压力并不大。比对、压缩的操作是在发起备份的服务器上进行的,这也在一定程度上把计算的负载很好的分摊了下去,即使是对一定规模的服务器集群进行备份,也不会对 borg 的服务端产生计算压力,borg 服务端只要准备好足够的存储空间即可。 ...

六月 27, 2023

Terraform 和云资源管理

前言 过去一年在前公司(电信)写了很多基础设施的自动化的实现,主要是通过 Ansible 将以往手动部署的中间件代码化,实现中间件的高效部署和持续运维。但像云服务器,域名等云资源,还是通过人工在控制台点点点来完成的。过去新机房的建设,近万台服务器,全是靠人工点出来的。 业界已经有成熟的工具:Terraform,国内的云公司比如:阿里云和腾讯云,也都有完善的支持了。这里记录一下 Arch Linux DevOps 团队的实现和我本地的实践。 本文会包含: 云资源如何代码化 Terraform 代码如何实现本地 AK、SK 等加密信息的加密存储 IaC & Terraform Terraform 介绍 Terraform 是声明式的(类似 K8s),基于自己的描述语言:HCL。比如有 10 台服务器,那么在存放 HCL 的基础设施代码仓库里,就会有 10 台服务器对应的安全组/规格/镜像的声明(当然,为了避免重复代码,会使用模块进行抽象)。 Terraform HCL 只声明必要的项,一些非必要的项,比如实例的 ID,镜像的 ID,会作为状态,存放在一个叫 state backend 的地方,通过本地的 HCL 代码配合 state backend 中的数据一起,将云资源所有信息声明出来。 默认 state backend 是执行者本地的一份 tfstate 结尾的文件。本地文件会导致一个问题,如果其他人想要获得当前所有云设施的最新状态,就需要跟之前的执行者索取他本地最新的 state 文件。因此,团队内一般会使用 remote state backend,这可以是一个数据库或者 S3(AWS 对象存储服务)。比如我本地就是用 PostgreSQL 来作为 remote state backend。所有基础设施代码的贡献者,确保能安全的访问到 PG 和对象存储即可。 即使使用了 remote state backend,本地还是会有 tfstate 文件,但将只包含 remote state backend 的连接信息,不包含云资源的补充信息。本地 tfstate 文件的信息在初始化 Terraform 时写入,比如我本地的 Terraform 首次初始化的命令如下: ...

二月 15, 2023

基础设施代码化

前言 Arch Linux 和 Rust 这两个开源组织的基础设施代码是开源的,那么,在实现基础设施代码开源的时候,如何保证私密信息安全呢? 实现在这里: Arch Linux infrastructure rust simpleinfra Arch Linux 使用 ansible-vault 和 gnupg 来管理私密信息,包括 Terraform 的 ak/sk/token。 Rust Team 使用 aws sts 实现权限管理。使用 aws ssm 来管理 Ansible 和 Terraform 中的私密信息。 Terraform 的 state 保存在 S3 上。 Arch Linux 团队的实践 关于 Ansible 的部分 Arch Linux 是通过 ansible.cfg 中的: vault_identity_list 来实现。 vault_identity_list 是一个逗号分隔的数组,可以传入多份包含密码的文件, 也可以传入多份可执行文件(该文件需要具备可执行权限),会是这样的形式: default@misc/vault-keyring-client.sh,super@misc/vault-keyring-client.sh 实际含义是,依次用如下的形式调用可执行文件: vault-keyring-client.sh --vault-id default vault-keyring-client.sh --vault-id super 只要可执行的脚本将密钥打印到标准输出即可。因此,我们就可以: 将密钥通过 gnupg 加密到一份文件内,存储到 gitlab 上,通过 bash 封装 gnupg 进行解密 将密钥存放在 1password,通过 bash 脚本封装 1password 命令行解密 Arch Linux 团队用的就是第一种方案,见: ...

二月 7, 2023

自建虚拟化

我的基础设施环境主要靠我家局域网内一台 7x24 小时运行的工作站支撑,我平时使用的基础设施,比如:gitlab、gitlab-runner、jira 甚至是现在你正在访问的博客站点,都是运行在这台工作站上的。这台工作站基于 Arch Linux,部署了 libvirt 虚拟化,不同的基础设施运行在彼此独立的虚拟机内。 下面简单介绍一下我平时是如何使用这个虚拟化的。 关于网络 我的虚拟化使用的是 bridge 网络模式,所以任何一台虚拟机都可以直接拿到局域网 IP,如何配置可参考:archwiki systemd-networkd#bridge-interface 关于系统和镜像 我的所有虚拟机也是 Arch Linux 系统。在虚拟化的宿主机上准备了一个 Arch Linux 虚拟机作为模板(模板镜像的准备使用了 virt-sysprep 这个工具),其他的虚拟机的镜像都是从模板镜像克隆出来的。虚拟机的镜像文件来自 Arch 官方,下载地址如下:Arch-Linux-x86_64-basic.qcow2 如何基于模板机创建实例 列出所有的虚拟机 virsh list --all 模板机关机备用 virsh shutdown template 基于模板机(我这里的模板机名字是:template)克隆出所需的主机 virt-clone --auto-clone --original template --name demo 镜像准备,避免 machine-id、ssh-host-key 等冲突问题(这步是必须的) virt-sysprep -d demo [可选] 为了后面能够通过 SSH 免密登录,所以在准备镜像的时候,我会顺便注入我的公钥,命令如下: virt-sysprep \ --ssh-inject root:string:'ssh-rsa AAAAB... jinmiaoluo@gmail.com' \ -d demo 启动虚拟机操作如下: virsh start demo [可选] 启动虚拟机并通过 console 方式管理虚拟机,操作如下(ctrl+] 可退出 console): ...

一月 27, 2023

可持续运维:质量、安全、效率

前言 过去手动部署 1 个高可用 apollo 集群并验证往往需要 1 ~ 2 个工作日,现在1 个工作日(7小时)可以部署 24 套,部署一套只需 18 分钟,并且所有集群都是生产就绪的,如何实现的? TL;DR 基于 vscode 的统一开发环境 基于 libvirtd 的配套测试环境 基于 wireguard 的私网 gitlab 和生产服务器集群加密通信虚拟局域网 基于 gitlab 的多分支开发模式 基于 gitlab ci 的运维代码自动同步 统一的开发环境 & 可重复的测试环境 在我司办公区机房有一台 Linux 物理服务器,我使用这台服务器作为统一开发环境,平时所有的 ansible 代码编写工作都是通过 vscode remote development 登录这台物理服务器完成。下面是常见的 2 种访问方式: 每一个开发者会有自己的一个 Linux 普通用户,开发者只需在自己的电脑上安装好 vscode,通过 vscode remote development 插件和自己在服务器的普通账号 ssh 连接物理服务器即可, vscode 会在各自的开发者用户下运行 vscode server 进程,因为 vscode 实际上都跑在同一台物理服务器上,所以其他开发者就有了跟我一模一样的 ansible 开发环境。 ...

十二月 3, 2022

可持续运维:运维代码化中的数据与操作

这是上一篇的展开说说。 可持续运维解决的几个问题: 一,运维代码化后,运维操作相关的代码可复用。比如:同一套运维操作代码,在不同的服务器上都可以使用。只需拷贝一份运维操作相关的代码,执行一遍,就可以得到完全相同的 2 套服务; 二,运维代码化后,运维操作相关的代码可叠加使用。比如:安装 kafka 集群为例。部署 kafka 需要先安装 zookeeper,部署 codis 集群也需要安装 zookeeper。zookeeper 的运维操作代码化后,我们就可以在 kafka 和 codis 的运维操作代码中直接调用 zookeeper 的运维操作代码,类似拼积木一般,无需重复实现 zookeeper 的运维操作代码; 三、运维代码化后,运维数据可按需传入。比如:在不同的机房部署的 codis 集群,无论是密码还是集群名字都是不同的。代码化运维,运维数据会通过 jinja2 等模板语言抽象成变量;部署时,按需传入不同的变量值,就实现了不同 codis 集群的部署,从而实现了运维代码的自定义,提高了运维代码化的兼容性; 四、运维代码化后,运维数据的加密存储。比如:上一步提到了 codis 集群的数据,其中数据分为普通数据和私密数据,比如前面,codis 集群的名字就是普通数据,codis 集群的密码就是私密数据。运维代码化无论是普通数据还是加密数据,都会直接存放在 Git 等版本控制系统中,这样可以全面、简单的记录所有运维的操作,但私密数据是经过加密的,如下图: 普通数据 私密数据(未解密) 私密数据(已解密) 可以看到,私密数据,在没有解密的时候,是一串密文。无论是普通数据还是私密数据(解密后的),其实都是变量。运维数据加密存储可以实现人员权限的管理。比如,我们可以控制哪些人的公钥(一个人或多个人)可以解开私密数据。有权限的人(内部人员)才能成功的执行运维代码(实际情况中还会通过 SSH 公私钥实现更精细的服务器权限管理,管理谁可以操作哪些服务器,而运维数据的加密存储则是对内部数据的保护)。 运维数据加密存储也为运维协作带来可能,因为运维仓库内,实际上就只有运维操作和安全的运维数据。另外,可以把开源看作是大规模协作的一种形式,这种形式,不是走的最快,但会走得最远。 五、运维代码化后,运维操作的持续迭代。我喜欢使用开源软件,但维护几个、几十个开源软件的运行环境是痛苦的。举个例子:我本地的 Nginx 都是 HTTPS 加密的,这里就离不开 lego 和 dns-01 实现的自动证书申请和续期。我的内网 nginx、外网 nginx、gitlab、jira 都有一份证书,都需要创建和配置自动证书刷新,这是很消耗精力的。几个原因,一个是开源软件的持续迭代往往是 github、gitlab,国内网络不友好,下载更新体验差;其次,几个,几十个开源软件的运行环境持续更新,运维操作没有代码化的时候,手动运维时间和精力成本太大了,并且还有不少重复操作可能导致犯错。因此,将运维操作代码化,在可控人力成本(我一个人)条件下,实现稳定、高效、持续的更新非常重要,而这离不开 Git 和 CI 的支持。 我现在只需要在安装 nginx、gitlab、jira 的 playbook 内,调用这块的运维操作代码,如下图: ...

十一月 25, 2022

可持续运维

最近在看 archlinux infrastructure 仓库中的代码,这个仓库是 archlinux 运维开发团队的运维仓库, 他们以代码化的方式实现了可持续的运维。 可持续的运维意味着什么: 随着时间的流逝和运维人员更换,运维操作不会丢失,服务器不会成为黑盒; 无论服务器是 1 台还是 1 万台,都能保证长期的可操作、可维护、强一致性。这里的例子有 k8s 集群持续升级到安全版本,无论是一个还是多个集群,中间件的升级方式基本一致(服务的持续更新); 新人可通过阅读运维代码,实现对现有服务、架构的了解,具备运维代码技能基础后(面试通过后),即具备持续运维的能力(人力资源的持续更新); 这里的代码化,主要是通过 ansible,以 yaml 的方式,将服务器的状态(跑什么服务,需要什么配置等)保存到 git 版本控制系统内, 并通过 gitlab 进行协作和持续迭代。 代码化运维的优势: 第一、版本化优势。因为所有的运维操作都通过 ansible 记录到了 gitlab 仓库,任何公司内部员工都可以知道服务器上发生的所有改动。比如: 可通过 git 查到某台服务器上的某个服务是怎么部署的、何时部署的、谁做的部署或者改动 可直接在仓库内确认服务器是否需要更新配置而无须登陆任何生产服务器(手动登录服务器是危险的) 可直接在一个仓库内查到所有架构信息。避免架构黑盒对梳理、优化运维架构会有非常大的作用 第二、服务器状态版本化。以 nginx 集群配置为例,nginx 集群状态以相应的 git commit 保存在 gitlab 内,如果 nginx 的改动导致了故障,可以通过 git checkout <commit_id> 快速的回退 nginx 的运维代码,重新执行 ansible 即可恢复服务。有的人会问,我在改动 nginx 配置的时候: cp nginx.conf nginx.conf.bak 故障时: cp -f nginx.conf.bak nginx.conf && nginx -s reload 就好了。为何还需要代码化?一方面,试设想如果你的集群有 30 台,每台服务器上都要执行上述操作的时候,会出现大量的人为操作,出错的可能性变大了。其次,在持续运维的过程中,会涉及到多次改动,如果 30 台服务器,都要改 30 次,就会在服务器上存在 30 个不同的 nginx.conf.bak,这对排查问题是不利的(在版本化的运维内,可以通过 git diff <commit1> <commit2> nginx.conf 快速定位配置改动的差异)。 ...

十月 24, 2022

Hello World

你好,世界 :)

十月 24, 2022