openziti/ziti-sdk-swift
GitHub: openziti/ziti-sdk-swift
面向 macOS 和 iOS 应用的 OpenZiti SDK,帮助 Apple 平台开发者将网络请求接入零信任 overlay 网络并实现透明路由。
Stars: 58 | Forks: 8

# Swift 版 Ziti SDK

一个使用 Swift 编程语言从 macOS 和 iOS 应用程序访问 Ziti 的 SDK。
此 SDK 提供了 __Ziti Tunnel C SDK__ 的 Swift 友好封装、一个用于拦截 HTTP 和 HTTPS 流量的 `URLProtocol` 实现,以及在应用程序中使用该 SDK 的示例。
# 用法
`Ziti` 类是访问 Ziti 网络的主要入口点。`Ziti` 实例在初始化时需要一个 `ZitiIdentity`。
使用 `Ziti.createConnection()` 创建 `ZitiConnection` 实例,以便 `ZitiConnection.dial(_:_:_:)` 服务或使用 `ZitiConnection.listen(_:_:_:)` 进行服务连接。
使用 `ZitiUrlProtocol` 拦截 HTTP 和 HTTPS 连接,并通过 Ziti 网络路由它们。
## 注册
`ZitiIdentity` 是在 Ziti 网络的注册过程中创建的。`Ziti` 支持使用由您的 Ziti 网络管理员提供的一次性 JWT 进行注册。
`Ziti.enroll(_:_:)` 方法会验证 JWT 是否已正确签名,创建私钥并将其存储在 keychain 中,向 controller 发起证书签名请求 (CSR),并将生成的证书存储在 keychain 中。
__Swift__
```
import CZiti
let jwtFile = <...>
let outFile = <...>
Ziti.enroll(jwtFile) { zid, zErr in
guard let zid = zid else {
fputs("Invalid enrollment response, \(String(describing: zErr))\n", stderr)
exit(-1)
}
guard zid.save(outFile) else {
fputs("Unable to save to file \(outFile)\n", stderr)
exit(-1)
}
print("Successfully enrolled id \"\(zid.id)\" with controller \"\(zid.ztAPI)\"")
}
```
__Objective-C__
```
#import "CZiti-Swift.h"
NSString *jwtFile = <...>
NSString *outFile = <...>
[Ziti enroll:jwtFile : ^(ZitiIdentity *zid, ZitiError *zErr) {
if (zErr != NULL) {
// Handle error
return;
}
if (![zid save:outFile]) {
// Handle error
return;
}
}];
```
在上面的示例代码中,保存到 `outfile` 的身份文件包含了用于联系 Ziti controller 以及在本地访问 keychain 中的私钥和证书的信息。
## 运行 Ziti
典型的应用程序流程如下:
1. 检查已知位置是否存在存储的身份文件
2. 如果不存在,则发起注册(例如,提示用户输入一次性 JWT 注册文件的位置,或扫描 QR 码)
3. 当身份文件可用时,使用它创建并运行 `Ziti` 实例
`Ziti` 在一个 loop 上执行,类似于 `Foundation` 的 `Runloop`。`Ziti.run(_:)` 方法本质上是进入一个处理 Ziti 事件的无限循环,并且只有在 `Ziti` 被关闭后才会退出。
提供 `Ziti.runAsync(_:)` 方法是为了方便起见,用于生成一个新线程并调用 `Ziti.run(_:)`。
__Swift__
```
let zidFile = <...>
guard let ziti = Ziti(fromFile: zidFile) else {
print("Unable to create Ziti identity from file \(zidFile)")
return
}
ziti.runAsync { zErr in
guard zErr == nil else {
print("Unable to run Ziti: \(String(describing: zErr!))")
return
}
print("Successfully initialized Ziti!")
}
```
__Objective-C__
```
NSString *zidFile = <...>
Ziti *ziti = [[Ziti alloc] initFromFile:[self zidFile]];
if (ziti != NULL) {
[ziti runAsync: ^(ZitiError *zErr) {
if (zErr != NULL) {
// Handle error
return;
}
[ZitiUrlProtocol register:ziti :10000];
}];
}
```
要在运行 Ziti 的线程上执行代码,请使用 `perform(_:)` 方法。
## 使用 `ZitiUrlProtocol`
该 SDK 还包含 `ZitiUrlProtocol`,它实现了一个 `URLProtocol`,用于拦截 Ziti 服务的 HTTP 和 HTTPS 请求,并通过 Ziti 网络路由它们。
`ZitiUrlProtocol` 应该作为 `Ziti.run(_:)` 的 `Ziti.InitCallback` 的一部分进行实例化,以确保在开始拦截服务之前 `Ziti` 已被初始化。
__Swift__
```
ziti.runAsync { zErr in
guard zErr == nil else {
// Handle error
return
}
ZitiUrlProtocol.register(ziti)
}
```
__Objective-C__
```
[ziti runAsync: ^(ZitiError *zErr) {
if (zErr != NULL) {
// Handle error
return;
}
[ZitiUrlProtocol register:ziti :10000];
}];
```
如果您使用自己的 `URLSession` 而不是 `URLSession.shared`,则需要在您的 `URLSession` 配置中配置 `ZitiUrlProtocol`:
```
let configuration = URLSessionConfiguration.default
configuration.protocolClasses?.insert(ZitiUrlProtocol.self, at: 0)
urlSession = URLSession(configuration:configuration)
```
另请参阅 `Xcode` Quick Help 面板中提供的 `CZiti` 模块中的文档。
# 将 `CZiti` 添加为依赖项
`CZiti` 被构建到一个 XCFramework (`CZiti.xcframework`) 中,其中包含适用于每个平台和架构的静态库 (`libCZiti.a`)。
请注意,`CZiti` 不是为 Bitcode 构建的,在为设备构建时,__Build Settings - Build Options__ 应该将 `Enable Bitcode` 设置为 `No`。
请注意,`CZiti` 在链接时依赖于 `libresolv.9.tbd` 和 `libz.1.tbd`,并且在 runtime 需要访问出站网络连接和 Apple Keychain。
## 通过 `Swift Package Manager`
请参阅 [ziti-sdk-swift-dist](https://github.com/openziti/ziti-sdk-swift-dist) 以获取从此存储库构建并作为 `.binaryTarget` 提供的 `CZiti.xcframework`。
## 使用本地构建的 CZiti
要在您的应用程序中体验对 CZiti 框架的修改,首先按照上述说明将 CZiti 模块添加为应用程序的依赖项,然后使用本地包覆盖 CZiti 框架。有关此过程的概述,请参阅[将包依赖项编辑为本地包](https://developer.apple.com/documentation/xcode/editing-a-package-dependency-as-a-local-package)。
我使用了以下步骤在 ziti-tunnel-apple 项目中用本地构建的版本覆盖 CZiti:
1. 构建 CZiti 框架。您可能想要为调试而构建:
$ CONFIGURATION=Debug ./build_all.sh
完成后,构建将位于 ./dist/CZiti.xcframework 中。
2. 为本地 CZiti 框架创建 Package.swift:
cat > ./dist/Package.swift < 0.1'
end
target 'SomeTarget-iOS-Target'
use_frameworks!
platform :ios, '13.4'
pod 'CZiti-iOS', '~> 0.1'
end
```
有关 Cocoapods 的更多信息,请查看[官方文档](http://guides.cocoapods.org/using/getting-started.html)。
## 通过 `libCZiti.a`
* 按照以下构建步骤创建 `libCZiti.a`
* 将 `libCZiti.a` 库添加到您项目的 **Frameworks and Libraries** 中,并确保它列在您项目的 **Build Phases** 中的 **Link Binary with Libraries** 下。
* 您的 **Library Search Path** 和 **Swift Compiler Seatch Paths - Import Paths** 应该包含含有 `libCZiti.a` 和 `CZiti.swiftmodule/` 的目录
* 当此项目从 `Xcode` 构建时,`CZiti-Swift.h` 文件会被复制到 `$(PROJECT_ROOT)/include/$(PLATFORM)`(例如,`./include/iphoneos`)。从 `Xcode` 或通过 `build_all.sh` 构建后,也可以在 `./DerivedData` 下的 `DerivedSources` 目录中找到 `CZiti-Swift.h`。从 Objective-C 使用 `CZiti` 需要此文件。您的 __Search Paths - Header Search Paths__ 必须包含含有 `CZiti-Swift.h` 的目录。
* 检查此存储库中示例应用程序的配置,以获取有关库和路径的相关构建设置
## 示例
此存储库包含一些使用该库的示例:
- [`ziti-mac-enroller`](ziti-mac-enroller/main.swift) 是一个实用程序,它将使用提供的一次性 JWT token 注册身份。它可以选择性地更新 keychain,以信任 Ziti controller 使用的 CA pool
- [`sample-mac-host`](sample-mac-host/main.swift) 是一个命令行实用程序,可以作为指定 Ziti server 的 client 或 server 运行
- [`sample-ios`](cziti.sample-ios/README.md) 练习使用 `ZitiUrlProtocol` 拦截 `URLSesson` 请求,通过 Ziti 路由它们,并显示结果
- [`sample-ios-objc`](sample-ios-objc/README.md) 演示了如何使用 __Objective-C__ 来运行 `ZitiUrlProtocol`
# 构建
## 更新 `xcconfig` 设置
创建一个名为 `Configs/workspace-settings-overrides.xcconfig` 的文件并填充适当的值。有关所有可能的值,请参阅 `Configs/workplace-settings.xcconfig`。
```
DEVELOPMENT_TEAM = XXXXXXXXXX
ORGANIZATION_PREFIX = ...
```
## 执行构建脚本
该项目依赖于 __Ziti Tunnel C SDK__,该 SDK 直接构建到库中。它作为 submodule 维护在 `./deps/ziti-tunnel-sdk-c`。请务必按照 deps/ziti-tunnel-sdk-c/BUILD.md 中的说明进行 vcpkg 设置。此项目期望 macOS 的构建位于 `./deps/ziti-tunnel-sdk-c/build-macosx-x86_64` 和 `./deps/ziti-tunnel-sdk-c/build-macosx-arm64`,而 iOS 的构建位于 `./deps/ziti-sdk-c/build-iphoneos-arm64`(如果是模拟器,则位于 `build-iphonesimulator-x86_64` 或 `build-iphonesimulator-arm64`)。
该项目包含 [`buid_all.sh`](build_all.sh) 脚本,它将从命令行为 `macosx`、`iphoneos` 和 `iphonesimulator` 平台构建项目。
构建静态库后,`build_all.sh` 脚本会执行 [`make_dist.sh`](make_dist.sh),在项目的 `./dist` 目录下创建一个名为 `CZiti.xcframework` 的 XCFramework。
这些脚本要求调用者的路径中包含以下可执行文件:
* `xcodebuild` 用于构建 `CZiti.xcodeproj` 中的 `CZiti-*` scheme,作为 `Xcode` 安装的一部分提供
* `xcpretty` 也用于构建 `CZiti.xcodeproj` 中的 `CZiti-*` scheme。(可以通过 `gem install xcpretty` 安装)
* `cmake` 用于构建 __Ziti Tunnel C SDK__ 依赖项。(可以通过 `brew install cmake` 安装)
```
$ git clone --recurse-submodules https://github.com/openziti/ziti-sdk-swift.git
$ cd ziti-sdk-swift
$ /bin/sh build_all.sh
```
默认情况下,脚本为 `Release` 配置进行构建。要为 `Debug` 构建,请执行
```
$ CONFIGURATION=Debug /bin/sh build_all.sh
```
生成的 `libCZiti.a` 和 `CZiti.swiftmodule` 位于 `./DerivedData` 的相应子目录中。
## 获取帮助
请使用这些社区资源来获取帮助。
- 阅读[文档](https://docs.openziti.io/docs/learn/introduction/)
- 参与 [Discourse](https://openziti.discourse.group/) 上的讨论
- 使用 GitHub [issues](https://github.com/openziti/ziti-sdk-swift/issues) 来跟踪 bug 和功能请求。
版权所有 NetFoundry Inc.
标签:CVE监控, iOS, Swift, VPN, 网络通信, 零信任网络