golang实现Google Zanzibar风格的全局授权系统插件库keto的使用

Golang 实现 Google Zanzibar 风格的全局授权系统插件库 Keto 的使用

Ory Keto 是第一个也是最受欢迎的开源实现,实现了"Zanzibar: Google 的全局一致性授权系统"!

快速开始

你可以使用 Docker 在本地运行 Ory Keto,或者使用 Ory CLI 来尝试 Ory Keto:

# 这个示例在 Bash 中效果最佳
bash <(curl https://raw.githubusercontent.com/ory/meta/master/install.sh) -b . ory
sudo mv ./ory /usr/local/bin/

# 或者如果你安装了 Homebrew
brew install ory/tap/cli

创建一个新项目(你也可以使用 Docker):

ory create project --name "Ory Keto Example"
export project_id="{设置为输出中的 ID}"

使用 Ory 权限语言创建命名空间

# 编写一个简单的配置,包含一个命名空间
echo "class Document implements Namespace {}" > config.ts

# 应用该配置
ory patch opl --project $project_id -f file://./config.ts

# 创建一个关系,授予 tom 访问文档的权限
echo "Document:secret#read@tom" \
  | ory parse relation-tuples --project=$project_id --format=json - \
  | ory create relation-tuples --project=$project_id -

# 列出所有关系
ory list relation-tuples --project=$project_id
# 输出:
#   NAMESPACE	OBJECT	RELATION NAME	SUBJECT
#   Document	secret	read		tom
#
#   NEXT PAGE TOKEN
#   IS LAST PAGE	true

Golang 示例代码

下面是一个使用 Golang 客户端与 Keto 交互的完整示例:

package main

import (
	"context"
	"fmt"
	"log"

	keto "github.com/ory/keto-client-go"
)

func main() {
	// 创建 Keto 客户端
	cfg := keto.NewConfiguration()
	cfg.Servers = []keto.ServerConfiguration{
		{
			URL: "http://localhost:4466", // Keto 服务地址
		},
	}
	client := keto.NewAPIClient(cfg)

	// 创建关系元组
	rel := keto.RelationTuple{
		Namespace: "Document",
		Object:    "secret",
		Relation:  "read",
		Subject:   "tom",
	}

	// 创建关系
	_, _, err := client.WriteApi.CreateRelationTuple(context.Background()).RelationTuple(rel).Execute()
	if err != nil {
		log.Fatalf("Failed to create relation tuple: %v", err)
	}

	// 检查权限
	allowed, _, err := client.PermissionApi.CheckPermission(context.Background()).
		Namespace("Document").
		Object("secret").
		Relation("read").
		Subject("tom").
		Execute()
	if err != nil {
		log.Fatalf("Failed to check permission: %v", err)
	}

	fmt.Printf("Is allowed: %v\n", allowed)
}

安装

前往文档了解安装 Ory Keto的各种方法。

生态系统

我们基于几个指导原则构建 Ory 架构:

  • 最小依赖
  • 随处运行
  • 轻松扩展
  • 最小化人为和网络错误的可能性

Ory 的架构设计最适合在 Kubernetes、CloudFoundry、OpenShift 等容器编排系统上运行。

安全

如果你认为发现了安全漏洞,请不要在论坛、聊天或 GitHub 上公开讨论。你可以在我们的security.txt中找到负责任披露的所有信息。

开发

我们鼓励所有贡献,并建议你阅读我们的贡献指南

依赖

你需要 Go 1.19+ 和(用于测试套件):

  • Docker 和 Docker Compose
  • GNU Make 4.3
  • NodeJS / npm >= v7

从源代码安装

make install

运行测试

有两种类型的测试可以运行:

  • 短测试(不需要像 PostgreSQL 这样的 SQL 数据库)
  • 常规测试(需要 PostgreSQL、MySQL、CockroachDB)

短测试

短测试运行相当快。你可以一次性测试所有代码:

go test -short -tags sqlite ./...

或者只测试特定模块:

go test -tags sqlite -short ./internal/check/...

常规测试

常规测试需要数据库设置。我们建议使用:

source ./scripts/test-resetdb.sh
go test -tags sqlite ./...

构建 Docker

你可以使用以下命令构建开发 Docker 镜像:

make docker

更多关于golang实现Google Zanzibar风格的全局授权系统插件库keto的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang实现Google Zanzibar风格的全局授权系统插件库keto的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


使用Go实现Google Zanzibar风格的授权系统(Keto)

Google Zanzibar是一种全球分布式授权系统,为Google Drive、YouTube等产品提供权限管理。Keto是Zanzibar的开源实现,下面我将介绍如何在Go中使用Keto构建授权系统。

Keto简介

Keto是一个实现了Zanzibar论文中核心概念的授权系统,主要特点包括:

  • 基于关系的访问控制(ReBAC)
  • 全局一致性
  • 高性能和可扩展性
  • 支持复杂的权限检查

安装Keto客户端

首先安装Keto Go客户端:

go get github.com/ory/keto-client-go

基本使用示例

1. 初始化客户端

package main

import (
	"context"
	"fmt"
	keto "github.com/ory/keto-client-go"
)

func main() {
	configuration := keto.NewConfiguration()
	configuration.Servers = []keto.ServerConfiguration{
		{
			URL: "http://localhost:4466", // Keto服务地址
		},
	}
	
	client := keto.NewAPIClient(configuration)
	ctx := context.Background()
	
	// 下面的示例将使用这个client
}

2. 定义关系元组

Zanzibar/Keto使用关系元组(relation tuples)来表示权限,格式为:namespace:object#relation@subject

// 添加关系元组
func addRelationTuple(client *keto.APIClient, ctx context.Context) {
	tuple := keto.RelationQuery{
		Namespace: "files",
		Object:    "file1",
		Relation:  "view",
		SubjectId: "user1",
	}
	
	_, _, err := client.WriteApi.CreateRelationTuple(ctx).RelationQuery(tuple).Execute()
	if err != nil {
		fmt.Printf("Error creating relation tuple: %v\n", err)
		return
	}
	fmt.Println("Relation tuple created successfully")
}

3. 检查权限

// 检查权限
func checkPermission(client *keto.APIClient, ctx context.Context) {
	check := keto.GetCheckRequest{
		Namespace: "files",
		Object:    "file1",
		Relation:  "view",
		SubjectId: "user1",
	}
	
	resp, _, err := client.PermissionApi.CheckPermission(ctx).GetCheckRequest(check).Execute()
	if err != nil {
		fmt.Printf("Error checking permission: %v\n", err)
		return
	}
	
	if resp.GetAllowed() {
		fmt.Println("Permission granted")
	} else {
		fmt.Println("Permission denied")
	}
}

4. 扩展关系

Keto支持定义关系之间的继承:

// 定义继承关系
func addInheritance(client *keto.APIClient, ctx context.Context) {
	// 管理员可以执行所有操作
	adminTuple := keto.RelationQuery{
		Namespace: "files",
		Object:    "file1",
		Relation:  "admin",
		SubjectId: "user2",
	}
	
	// 定义admin包含view权限
	inheritanceTuple := keto.RelationQuery{
		Namespace: "files",
		Object:    "file1",
		Relation:  "view",
		SubjectSet: &keto.SubjectSet{
			Namespace: "files",
			Object:    "file1",
			Relation:  "admin",
		},
	}
	
	_, _, err := client.WriteApi.CreateRelationTuple(ctx).RelationQuery(adminTuple).Execute()
	if err != nil {
		fmt.Printf("Error creating admin tuple: %v\n", err)
		return
	}
	
	_, _, err = client.WriteApi.CreateRelationTuple(ctx).RelationQuery(inheritanceTuple).Execute()
	if err != nil {
		fmt.Printf("Error creating inheritance tuple: %v\n", err)
		return
	}
	
	fmt.Println("Inheritance relationship created")
}

5. 批量操作

// 批量操作
func batchOperations(client *keto.APIClient, ctx context.Context) {
	// 创建多个关系
	tuples := []keto.RelationQuery{
		{
			Namespace: "files",
			Object:    "file2",
			Relation:  "view",
			SubjectId: "user1",
		},
		{
			Namespace: "files",
			Object:    "file3",
			Relation:  "edit",
			SubjectId: "user2",
		},
	}
	
	for _, tuple := range tuples {
		_, _, err := client.WriteApi.CreateRelationTuple(ctx).RelationQuery(tuple).Execute()
		if err != nil {
			fmt.Printf("Error creating tuple: %v\n", err)
			continue
		}
	}
	
	fmt.Println("Batch operations completed")
}

实际应用示例

下面是一个更完整的示例,模拟文件共享系统:

type FileSharingSystem struct {
	client *keto.APIClient
	ctx    context.Context
}

func NewFileSharingSystem() *FileSharingSystem {
	cfg := keto.NewConfiguration()
	cfg.Servers = []keto.ServerConfiguration{{URL: "http://localhost:4466"}}
	return &FileSharingSystem{
		client: keto.NewAPIClient(cfg),
		ctx:    context.Background(),
	}
}

func (f *FileSharingSystem) ShareFile(fileID, userID, permission string) error {
	tuple := keto.RelationQuery{
		Namespace: "files",
		Object:    fileID,
		Relation:  permission,
		SubjectId: userID,
	}
	
	_, _, err := f.client.WriteApi.CreateRelationTuple(f.ctx).RelationQuery(tuple).Execute()
	return err
}

func (f *FileSharingSystem) CheckAccess(fileID, userID, permission string) (bool, error) {
	check := keto.GetCheckRequest{
		Namespace: "files",
		Object:    fileID,
		Relation:  permission,
		SubjectId: userID,
	}
	
	resp, _, err := f.client.PermissionApi.CheckPermission(f.ctx).GetCheckRequest(check).Execute()
	if err != nil {
		return false, err
	}
	return resp.GetAllowed(), nil
}

func main() {
	fss := NewFileSharingSystem()
	
	// 分享文件
	err := fss.ShareFile("report.pdf", "alice", "view")
	if err != nil {
		fmt.Printf("Error sharing file: %v\n", err)
		return
	}
	
	// 检查权限
	allowed, err := fss.CheckAccess("report.pdf", "alice", "view")
	if err != nil {
		fmt.Printf("Error checking access: %v\n", err)
		return
	}
	
	if allowed {
		fmt.Println("Alice can view the report")
	} else {
		fmt.Println("Alice cannot view the report")
	}
}

最佳实践

  1. 命名空间设计:合理规划命名空间,如按资源类型划分
  2. 关系设计:设计清晰的关系层次结构
  3. 批量操作:尽量使用批量接口减少网络开销
  4. 缓存:对频繁检查的权限考虑本地缓存
  5. 监控:监控权限检查的延迟和错误率

Keto提供了强大的权限管理能力,特别适合需要复杂权限关系的分布式系统。通过合理设计关系模型,可以实现灵活的权限控制策略。

回到顶部