Skip to content

Commit

Permalink
feat: initial commit.
Browse files Browse the repository at this point in the history
  • Loading branch information
aegistudio committed Jan 26, 2022
0 parents commit 1d1fe58
Show file tree
Hide file tree
Showing 22 changed files with 1,383 additions and 0 deletions.
13 changes: 13 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Copyright 2022 Chaitin Tech

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

The extent of the "Software" is limited to the published content of "https://github.com/chaitin/libveinmind" repository, excluding the external but hyperlinked contents and the libVeinMind related trademarks.

The users must obey external contents' piecewise license.

The libVeinMind, libveinmind, VeinMind, veinmind, "问脉", "问脉容器安全", and similar or other related terminologies are trademarks of Chaitin Tech. The users MUST neither claim the trademarks to be belonged to theirs, nor utilize the trademarks to advocate or merchandise their own products or themselves.
37 changes: 37 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# libVeinMind: 问脉容器感知与安全 SDK

<p>
<img src="https://img.shields.io/github/release/chaitin/libveinmind.svg" />
<img src="https://img.shields.io/github/release-date/chaitin/libveinmind.svg?color=blue&label=update" />
</p>

> 容器安全见筋脉,望闻问切治病害。
问脉 (TM) SDK 提供了容器安全领域所关心的容器、镜像和运行时等对象的信息获取、镜像内容器访问等相关操作。并进行合理的抽象以提高容器安全工具对 Docker、Containerd 和 Kubernetes 等不同容器产品的兼容性,简化容器安全工具的开发和维护。

问脉 SDK 是问脉 (TM) 容器安全开源工具箱编译和运行所需的依赖,您也可以基于问脉 SDK 开发符合自己需求的容器安全工具。

问脉 SDK 中的接口部分在本仓库中进行了开源,实现部分采取免费闭源的方式提供给用户。

## 快速开始

要使用问脉 SDK 需要先安装对应平台下的 SDK 软件包。以 Ubuntu 和 Debian 为例,SDK 的安装和配置步骤如下:

1. 添加 libVeinMind 的 APT 包源并更新 APT 包列表和索引,通过执行以下指令:

```bash
echo 'deb [trusted=yes] https://download.veinmind.tech/libveinmind/ ./' | sudo tee /etc/apt/sources.list.d/libveinmind.list
sudo apt-get update
```

2. 执行指令 `sudo apt-get install libveinmind-dev` 以开始安装问脉。

3. 安装过程中,需阅读并同意问脉 SDK 的用户协议,方可完成 SDK 的安装与配置。

## 联系我们

1. 您可以通过 GitHub Issue 直接进行 Bug 反馈和功能建议。

2. 您扫描下方二维码可以通过添加问脉小助手,以加入问脉用户讨论群进行详细讨论:

![](docs/veinmind-group-qrcode.jpg)
Binary file added docs/veinmind-group-qrcode.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module github.com/chaitin/libveinmind

go 1.14

require (
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.0.2
)
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM=
github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
53 changes: 53 additions & 0 deletions go/containerd/containerd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Package containerd is the API implementation on containerd.
package containerd

import (
api "github.com/chaitin/libveinmind/go"
"github.com/chaitin/libveinmind/go/pkg/behaviour"
"github.com/chaitin/libveinmind/go/pkg/binding"
)

// Containerd is the connection established with a
// containerd runtime.
type Containerd struct {
behaviour.Closer
behaviour.Runtime
behaviour.FileSystem
runtime binding.Handle
}

// New a containerd runtime by parsing the configurations
// specified in "/var/lib/containerd" directory, assuming it is
// defaultly installed.
func New() (api.Runtime, error) {
h, err := binding.DockerNew()
if err != nil {
return nil, err
}
result := &Containerd{runtime: h}
result.Closer = behaviour.NewCloser(&result.runtime)
result.Runtime = behaviour.NewRuntime(&result.runtime)
result.FileSystem = behaviour.NewFileSystem(&result.runtime)
return result, nil
}

// Image represents a containerd image, which is guaranteed to
// be the result of docker.Docker.OpenImageByID.
type Image struct {
behaviour.Closer
behaviour.Image
behaviour.FileSystem
image binding.Handle
}

func (d *Containerd) OpenImageByID(id string) (api.Image, error) {
h, err := d.runtime.RuntimeOpenImageByID(id)
if err != nil {
return nil, err
}
result := &Image{image: h}
result.Closer = behaviour.NewCloser(&result.image)
result.Image = behaviour.NewImage(&result.image)
result.FileSystem = behaviour.NewFileSystem(&result.image)
return result, nil
}
80 changes: 80 additions & 0 deletions go/docker/docker.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// Package docker is the API implementation on docker.
package docker

import (
api "github.com/chaitin/libveinmind/go"
"github.com/chaitin/libveinmind/go/pkg/behaviour"
"github.com/chaitin/libveinmind/go/pkg/binding"
)

// Docker is the connection established with a docker runtime.
type Docker struct {
behaviour.Closer
behaviour.Runtime
behaviour.FileSystem
runtime binding.Handle
}

// New a docker runtime by parsing the configurations specified
// in "/etc/docker" directory, assuming it is defaultly installed.
func New() (api.Runtime, error) {
h, err := binding.DockerNew()
if err != nil {
return nil, err
}
result := &Docker{runtime: h}
result.Closer = behaviour.NewCloser(&result.runtime)
result.Runtime = behaviour.NewRuntime(&result.runtime)
result.FileSystem = behaviour.NewFileSystem(&result.runtime)
return result, nil
}

// Image represents a docker image, which is guaranteed to be
// the result of docker.Docker.OpenImageByID.
type Image struct {
behaviour.Closer
behaviour.Image
behaviour.FileSystem
image binding.Handle
}

func (d *Docker) OpenImageByID(id string) (api.Image, error) {
h, err := d.runtime.RuntimeOpenImageByID(id)
if err != nil {
return nil, err
}
result := &Image{image: h}
result.Closer = behaviour.NewCloser(&result.image)
result.Image = behaviour.NewImage(&result.image)
result.FileSystem = behaviour.NewFileSystem(&result.image)
return result, nil
}

func (i *Image) NumLayers() int {
return i.image.DockerImageNumLayers()
}

func (im *Image) GetLayerDiffID(i int) (string, error) {
return im.image.DockerImageGetLayerDiffID(i)
}

// Layer represents a containerd layer, which is guaranteed to
// be the result of docker.Image.OpenLayer.
type Layer struct {
behaviour.FileSystem
layer binding.Handle
}

func (im *Image) OpenLayer(i int) (*Layer, error) {
l, err := im.image.DockerImageOpenLayer(i)
if err != nil {
return nil, err
}
result := &Layer{layer: l}
result.FileSystem = behaviour.NewFileSystem(&result.layer)
return result, nil
}

func (l *Layer) ID() string {
return l.layer.DockerLayerID()
}
30 changes: 30 additions & 0 deletions go/filesystem.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package api

import (
"io"
"os"
"path/filepath"
)

// File abstracts an open file from container. Some behaviours
// might be masked due to potential incompatibility.
type File interface {
io.ReadWriteCloser
io.ReaderAt
io.WriterAt

Stat() (os.FileInfo, error)
}

// FileSystem abstracts the property of an object to visit its
// internal file system structure, which is usually prepared
// by the container runtime.
type FileSystem interface {
Open(path string) (File, error)
Stat(path string) (os.FileInfo, error)
Lstat(path string) (os.FileInfo, error)
Readlink(path string) (string, error)
EvalSymlink(path string) (string, error)
Readdir(path string) ([]os.FileInfo, error)
Walk(root string, walkFn filepath.WalkFunc) error
}
62 changes: 62 additions & 0 deletions go/package.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Package api defines the API outline for working with
// different container runtimes.
//
// The user should first establish some kind of connection
// as client with their desired container runtime. The
// client configuraton could be either by specifying it
// manually, or by recognizing them on the host first.
//
// After establishing a client connection with container
// runtime, the user could invoke the client API to enumerate
// containers and images by their IDs, and open one of these
// entities furtherly.
package api

import (
imageV1 "github.com/opencontainers/image-spec/specs-go/v1"
)

// Image is the open image object from a runtime.
type Image interface {
FileSystem

Close() error
ID() string

Repos() ([]string, error)
RepoRefs() ([]string, error)

OCISpecV1() (*imageV1.Image, error)
}

// Runtime is the connection established with a specific
// container runtime, depending on the implementation and
// container runtime internal nature.
type Runtime interface {
Close() error

// ListImageIDs attempt to enumerate the images by their
// IDs managed by the container runtime, which could be
// used to open the image.
ListImageIDs() ([]string, error)

// FindImageIDs attempt to match image ID by specifying
// their human readable identifiers. It must follow the
// following rules.
//
// 1. When pattern is image ID recognizable by this
// container runtime, it will be searched first.
// 2. When pattern is pure hexadecimal, the digest value
// portion will be matched.
// 3. When pattern is a single identifier, all images
// with the specified identifier will be matched.
// 4. When pattern is a repository path, all images with
// the specified repository but different versions
// will be matched.
// 5. When pattern is a named tagged or canonical
// reference, the whole portion will be matched.
FindImageIDs(pattern string) ([]string, error)

// OpenImageByID attempt to open a image by its ID.
OpenImageByID(id string) (Image, error)
}
4 changes: 4 additions & 0 deletions go/pkg/behaviour/behaviour.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// Package behaviour implements some common binding based
// interfaces by their behaviours, so that real entities
// can conveniently aggregate these behaviour into them.
package behaviour
Loading

0 comments on commit 1d1fe58

Please sign in to comment.