Merge branch 'master' into lint-md

This commit is contained in:
Ian Lewis
2020-01-17 01:47:38 -05:00
10311 changed files with 244653 additions and 196249 deletions
+83 -18
View File
@@ -1,7 +1,5 @@
HUGO := hugo
HUGO_VERSION := 0.53
HTMLPROOFER_VERSION := 3.10.2
NPM := npm
GCLOUD := gcloud
GCP_PROJECT := gvisor-website
@@ -15,7 +13,7 @@ CONTENT_SOURCE = $(wildcard content/*)
default: website
.PHONY: default
website: all-upstream app public/static
website: all-upstream app static-production
.PHONY: website
app: $(APP_TARGET)
@@ -45,16 +43,59 @@ content/docs/community/sigs: upstream/community $(wildcard upstream/community/si
$(APP_TARGET): public $(APP_SOURCE)
cp -a cmd/gvisor-website/$(patsubst public/%,%,$@) public/
public/static: compatibility-docs node_modules config.toml $(shell find archetypes assets content themes -type f | sed 's/ /\\ /g')
HUGO_ENV="production" $(HUGO)
static-production: hugo-docker-image compatibility-docs node_modules config.toml $(shell find archetypes assets content themes -type f | sed 's/ /\\ /g')
docker run \
--rm \
-e HUGO_ENV="production" \
-e USER="$(shell id -u)" \
-e HOME="/tmp" \
-u="$(shell id -u):$(shell id -g)" \
-v $(PWD):/workspace \
-w /workspace \
gcr.io/gvisor-website/hugo:$(HUGO_VERSION) \
hugo
.PHONY: static-production
static-staging: hugo-docker-image compatibility-docs node_modules config.toml $(shell find archetypes assets content themes -type f | sed 's/ /\\ /g')
docker run \
--rm \
-e HUGO_ENV="production" \
-e USER="$(shell id -u)" \
-e HOME="/tmp" \
-u="$(shell id -u):$(shell id -g)" \
-v $(PWD):/workspace \
-w /workspace \
gcr.io/gvisor-website/hugo:$(HUGO_VERSION) \
hugo \
-b "https://staging-$(shell git branch | grep \* | cut -d ' ' -f2)-dot-gvisor-website.appspot.com"
.PHONY: static-staging
node_modules: package.json package-lock.json
# Use npm ci because npm install will update the package-lock.json.
# See: https://github.com/npm/npm/issues/18286
$(NPM) ci
docker run \
--rm \
-e USER="$(shell id -u)" \
-e HOME="/tmp" \
-u="$(shell id -u):$(shell id -g)" \
-v $(PWD):/workspace \
-w /workspace \
--entrypoint 'npm' \
node ci
upstream/gvisor/bazel-bin/runsc/linux_amd64_pure_stripped/runsc: upstream-gvisor
cd upstream/gvisor && bazel build runsc
mkdir -p /tmp/gvisor-website/build_output
docker run \
--rm \
-v $(PWD)/upstream/gvisor:/workspace \
-v /tmp/gvisor-website/build_output:/tmp/gvisor-website/build_output \
-w /workspace \
--entrypoint 'sh' \
l.gcr.io/google/bazel \
-c '\
groupadd --gid $(shell id -g) $(shell id -gn) && \
useradd --uid $(shell id -u) --gid $(shell id -g) -ms /bin/bash $(USER) && \
su $(USER) -c "bazel --output_user_root=/tmp/gvisor-website/build_output build //runsc"'
bin/generate-syscall-docs: $(GEN_SOURCE)
mkdir -p bin/
@@ -65,10 +106,22 @@ compatibility-docs: bin/generate-syscall-docs upstream/gvisor/bazel-bin/runsc/li
.PHONY: compatibility-docs
check: check-markdown check-html
docker run \
-v $(shell pwd)/public:/public gcr.io/gvisor-website/html-proofer:$(HTMLPROOFER_VERSION) \
htmlproofer --disable-external --check-html public/static
.PHONY: check
check-markdown: node_modules $(CONTENT_SOURCE) compatibility-docs
npm run lint-md
docker run \
--rm \
-e USER="$(shell id -u)" \
-e HOME="/tmp" \
-u="$(shell id -u):$(shell id -g)" \
-v $(PWD):/workspace \
-v /tmp:/tmp \
-w /workspace \
--entrypoint 'npm' \
node run lint-md
.PHONY: check-markdown
check-html: website
@@ -76,18 +129,32 @@ check-html: website
.PHONY: check-html
# Run a local content development server. Redirects will not be supported.
devserver: all-upstream compatibility-docs
$(HUGO) server -FD --port 8080
devserver: hugo-docker-image all-upstream compatibility-docs
docker run \
--rm \
-e USER="$(shell id -u)" \
-e HOME="/tmp" \
-u="$(shell id -u):$(shell id -g)" \
-v $(PWD):/workspace \
-w /workspace \
-p 8080:8080 \
gcr.io/gvisor-website/hugo:$(HUGO_VERSION) \
hugo server \
-FD \
--bind 0.0.0.0 \
--port 8080
.PHONY: server
server: website
cd public/ && go run main.go --custom-domain localhost
.PHONY: server
# Deploy the website to App Engine.
deploy: $(APP_TARGET)
cd public && $(GCLOUD) app deploy
.PHONY: deploy
# Stage the website to App Engine at a version based on the git branch name.
stage: all-upstream app static-staging
# Disallow indexing staged content.
printf "User-agent: *\nDisallow: /" > public/static/robots.txt
cd public && $(GCLOUD) app deploy -v staging-$(shell git branch | grep \* | cut -d ' ' -f2) --no-promote
.PHONY: stage
# CI related Commmands
##############################################################################
@@ -96,16 +163,14 @@ deploy: $(APP_TARGET)
cloud-build:
gcloud builds submit --config cloudbuild.yaml .
# Build and push the hugo Docker image used by Cloud Build.
# Build the hugo Docker image.
hugo-docker-image:
docker build --build-arg HUGO_VERSION=$(HUGO_VERSION) -t gcr.io/gvisor-website/hugo:$(HUGO_VERSION) cloudbuild/hugo/
docker push gcr.io/gvisor-website/hugo:$(HUGO_VERSION)
.PHONY: hugo-docker-image
# Build and push the html-proofer image used by Cloud Build.
# Build the html-proofer image used by Cloud Build.
htmlproofer-docker-image:
docker build --build-arg HTMLPROOFER_VERSION=$(HTMLPROOFER_VERSION) -t gcr.io/gvisor-website/html-proofer:$(HTMLPROOFER_VERSION) cloudbuild/html-proofer/
docker push gcr.io/gvisor-website/html-proofer:$(HTMLPROOFER_VERSION)
.PHONY: htmlproofer-docker-image
clean:
+23 -43
View File
@@ -4,24 +4,14 @@ This repository holds the content for the gVisor website. It uses
[hugo](https://gohugo.io/) to generate the website and
[Docsy](https://github.com/google/docsy) as the theme.
## Requirements
## Using Github
Building the website requires the extended version of
[hugo](https://gohugo.io/) and [node.js](https://nodejs.org/) in order to
generate CSS files. Please install them before building.
The easiest way to contribute to the documentation is to use the "Edit this
page" link on any documentation page to edit the page content directly via
GitHub and submit a pull request. This should generally be done for changes to
a single page.
- Node.js >= 10.15.0 LTS
- hugo extended >= v0.53
## Contributing to Documentation
### Using Github
You can use the "Edit this page" link on any documentation page to edit the
page content directly via GitHub and submit a pull request. This should
generally be done for relatively small changes.
### Using Git
## Using Git
You can submit pull requests by making changes in a Git branch. See more
information on GitHub pull requests
@@ -32,47 +22,37 @@ Documentation is written in markdown with hugo extensions. Please read more
about [content management](https://gohugo.io/categories/content-management) in
the hugo documentation.
You can use the hugo web server for testing. This will start a webserver that
will rebuild the site when you make content changes:
### Requirements
```
make server
```
Building the website requires [Docker](https://www.docker.com/). Please
[install](https://docs.docker.com/install/) it before building.
Access the site at http://localhost:8080
### Building
## Building
If you are making changes to App Engine config or application code, you can
build the website using `make`. This will output the App Engine application
code, configuration, and html and CSS into the `public/` directory.
If you want to simply build the website, you can do that using `make`. This
will output the App Engine application code, configuration, and html and CSS
into the `public/` directory.
```
make
```
If you have Go installed you can run a local version of the website via the
`public/` directory.
### Testing
You can use the hugo web server for testing documentation or style changes.
This will start a webserver that will rebuild the site when you make content
changes:
```
cd public/
go run main.go
make devserver
```
Access the site at http://localhost:8080
## Troubleshooting
#### I get errors when building the website.
If you get the following errors you should check that you have the "extended"
version of Hugo. This is the version of hugo named "hugo\_extended" on the
[releases page](https://github.com/gohugoio/hugo/releases).
If you need to test all functionality including redirects you can start the App
Engine app locally. However, you will need to restart the app when making
content changes:
```
ERROR 2019/04/03 11:25:58 Failed to add template "partials/navbar.html" in path "/home/me/gvisor-website/layouts/partials/navbar.html": template: partials/navbar.html:5: function "resources" not defined
ERROR 2019/04/03 11:25:58 partials/navbar.html : template: partials/navbar.html:5: function "resources" not defined
ERROR 2019/04/03 11:25:58 Unable to locate template for shortcode "readfile" in page "docs/user_guide/docker.md"
ERROR 2019/04/03 11:25:58 Unable to locate template for shortcode "readfile" in page "docs/user_guide/oci.md"
ERROR 2019/04/03 11:25:58 Unable to locate template for shortcode "blocks" in page "_index.html"
make server
```
+1 -1
View File
@@ -13,7 +13,7 @@ RUN set -x \
libcurl \
libxml2-dev \
libxslt-dev \
openssh
openssh \
&& gem install \
html-proofer:${HTMLPROOFER_VERSION} \
nokogiri:1.10.1 \
+1 -2
View File
@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
runtime: go111
runtime: go112
handlers:
- url: /.*
@@ -21,4 +21,3 @@ handlers:
- url: /rebuild
secure: always
script: auto
login: admin
+15 -1
View File
@@ -71,6 +71,20 @@ var (
goGetHTML5 = `<!doctype html><html><head><meta charset=utf-8>` + goGetHeader + `<title>Go-get</title></head><body></html>`
)
// cronHandler wraps an http.Handler to check that the request is from the App
// Engine Cron service.
// See: https://cloud.google.com/appengine/docs/standard/go112/scheduling-jobs-with-cron-yaml#validating_cron_requests
func cronHandler(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Header.Get("X-Appengine-Cron") != "true" {
http.NotFound(w, r)
return
}
// Fallthrough.
h.ServeHTTP(w, r)
})
}
// wrappedHandler wraps an http.Handler.
//
// If the query parameters include go-get=1, then we redirect to a single
@@ -174,7 +188,7 @@ func registerRebuild(mux *http.ServeMux) {
mux = http.DefaultServeMux
}
mux.Handle("/rebuild", wrappedHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
mux.Handle("/rebuild", cronHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := context.Background()
credentials, err := google.FindDefaultCredentials(ctx, cloudbuild.CloudPlatformScope)
if err != nil {
+5 -1
View File
@@ -35,8 +35,12 @@ pygmentsStyle = "tango"
weight = -100
url = "/docs/"
[[menu.main]]
name = "GitHub"
name = "Blog"
weight = -99
url = "/blog/"
[[menu.main]]
name = "GitHub"
weight = -98
url = "https://github.com/google/gvisor"
# First one is picked as the Twitter card image if not set on page.
Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

+224
View File
@@ -0,0 +1,224 @@
---
date: 2019-11-18
title: "gVisor Security Basics - Part 1"
linkTitle: "gVisor Security Basics - Part 1"
description: ""
author: Jeremiah Spradlin & Zach Koopmans
---
# Part 1 - Introduction
This blog is a space for engineers and community members to share perspectives and deep dives on technology and design within the gVisor project.
Though our logo suggests were in the business of space exploration (or perhaps fighting sea monsters), were actually in the business of sandboxing Linux containers.
When we created gVisor, we had three specific goals in mind; _container-native security_, _resource efficiency_, and _platform portability_. To put it simply, gVisor provides _efficient defense-in-depth for containers anywhere_.
This post addresses gVisor's _container-native security_, specifically how gVisor provides strong isolation between an application and the host OS.
Future posts will address _resource efficiency_ (how gVisor preserves container benefits like fast starts, smaller snapshots, and less memory overhead than VMs) and _platform portability_ (run gVisor wherever Linux OCI containers run).
Delivering on each of these goals requires careful security considerations and a robust design.
## What does “sandbox” mean?
gVisor allows the execution of untrusted containers, preventing them from adversely affecting the host. This means that the untrusted container is prevented from attacking or spying on either the host kernel or any other peer userspace processes on the host.
For example, if you are a cloud container hosting service, running containers from different customers on the same virtual machine means that compromises expose customer data. Properly configured, gVisor can provide sufficient isolation to allow different customers to run containers on the same host. There are many aspects to the proper configuration, including limiting file and network access, which we will discuss in future posts.
## The cost of compromise
gVisor was designed around the premise that any security boundary could potentially be compromised with enough time and resources. We tried to optimize for a solution that was as costly and time-consuming for an attacker as possible, at every layer.
Consequently, gVisor was built through a combination of intentional design principles and specific technology choices that work together to provide the security isolation needed for running hostile containers on a host. Well dig into it in the next section!
# Design Principles
gVisor was designed with some [common secure design principles](https://www.owasp.org/index.php/Security_by_Design_Principles) in mind: Defense-in-Depth, Principle of Least-Privilege, Attack Surface Reduction and Secure-by-Default[^1].
In general, Design Principles outline good engineering practices, but in the case of security, they also can be thought of as a set of tactics. In a real-life castle, there is no single defensive feature. Rather, there are many in combination: redundant walls, scattered draw bridges, small bottle-neck entrances, moats, etc.
A simplified version of the design is below ([more detailed version](https://gvisor.dev/docs/architecture_guide/))[^2]:
____
![Figure 1](./figure1.png)
Figure 1: Simplified design of gVisor.
____
In order to discuss design principles, the following components are important to know:
* runsc - binary that packages the Sentry, platform, and Gofer(s) that run containers. runsc is the drop-in binary for running gVisor in Docker and Kubernetes.
* Untrusted Application - container running in the sandbox. Untrusted application/container are used interchangeably in this article.
* Platform Syscall Switcher - intercepts syscalls from the application and passes them to the Sentry with no further handling.
* Sentry - The "application kernel" in userspace that serves the untrusted application. Each application instance has its own Sentry. The Sentry handles syscalls, routes I/O to gofers, and manages memory and CPU, all in userspace. The Sentry is allowed to make limited, filtered syscalls to the host OS.
* Gofer - a process that specifically handles different types of I/O for the Sentry (usually disk I/O). Gofers are also allowed to make filtered syscalls to the Host OS.
* Host OS - the actual OS on which gVisor containers are running, always some flavor of Linux (sorry, Windows/MacOS users).
It is important to emphasize what is being protected from the untrusted application in this diagram: the host OS and other userspace applications.
In this post, we are only discussing security-related features of gVisor, and you might ask, “What about performance, compatibility and stability?” We will cover these considerations in future posts.
## Defense-in-Depth
For gVisor, Defense-in-Depth means each component of the software stack trusts each other component as little as possible.
It may seem strange that we would want our own software components to distrust each other. But by limiting the trust between small, discrete components, each component is forced to defend itself against potentially malicious input. And when you stack these components on top of each other, you can ensure that multiple security barriers must be overcome by an attacker.
And this leads us to how Defense-in-Depth is applied to gVisor: no single vulnerability should compromise the host.
In the “Attackers Advantage / Defenders Dilemma,” the defender must succeed all the time while the attacker only needs to succeed once. Defense in Depth inverts this principle: once the attacker successfully compromises any given software component, they are immediately faced with needing to compromise a subsequent, distinct layer in order to move laterally or acquire more privilege.
For example, the untrusted container is isolated from the Sentry. The Sentry is isolated from host I/O operations by serving those requests in separate processes called Gofers. And both the untrusted container and its associated Gofers are isolated from the host process that is running the sandbox.
An additional benefit is that this generally leads to more robust and stable software, forcing interfaces to be strictly defined and tested to ensure all inputs are properly parsed and bounds checked.
## Least-Privilege
The principle of Least-Privilege implies that each software component has only the permissions it needs to function, and no more.
Least-Privilege is applied throughout gVisor. Each component and more importantly, each interface between the components, is designed so that only the minimum level of permission is required for it to perform its function. Specifically, the closer you are to the untrusted application, the less privilege you have.
____
![Figure 2](./figure2.png)
Figure 2: runsc components and their privileges.
____
This is evident in how runsc (the drop in gVisor binary for Docker/Kubernetes) constructs the sandbox. The Sentry has the least privilege possible (it cant even open a file!). Gofers are only allowed file access, so even if it were compromised, the host network would be unavailable. Only the runsc binary itself has full access to the host OS, and even runscs access to the host OS is often limited through capabilities / chroot / namespacing.
Designing a system with Defense-in-Depth and Least-Privilege in mind encourages small, separate, single-purpose components, each with very restricted privileges.
## Attack Surface Reduction
There are no bugs in unwritten code.
In other words, gVisor supports a feature if and only if it is needed to run host Linux containers.
### Host Application/Sentry Interface:
There are a lot of things gVisor does not need to do. For example, it does not need to support arbitrary device drivers, nor does it need to support video playback. By not implementing what will not be used, we avoid introducing potential bugs in our code.
That is not to say gVisor has limited functionality! Quite the opposite, we analyzed what is actually needed to run Linux containers and today the Sentry supports 237 syscalls[^3]<sup>,</sup>[^4], along with the range of critical /proc and /dev files. However, gVisor does not support every syscall in the Linux kernel. There are about 350 syscalls[^5] within the 5.3.11 version of the Linux kernel, many of which do not apply to Linux containers that typically host cloud-like workloads. For example, we don't support old versions of epoll (epoll_ctl_old, epoll_wait_old), because they are deprecated in Linux and no supported workloads use them.
Furthermore, any exploited vulnerabilities in the implemented syscalls (or Sentry code in general) only apply to gaining control of the Sentry. More on this in a later post.
### Sentry/Host OS Interface:
The Sentrys interactions with the Host OS are restricted in many ways. For instance, no syscall is “passed-through” from the untrusted application to the host OS. All syscalls are intercepted and interpreted. In the case where the Sentry needs to call the Host OS, we severely limit the syscalls that the Sentry itself is allowed to make to the host kernel[^6].
For example, there are many file-system based attacks, where manipulation of files or their paths, can lead to compromise of the host[^7]. As a result, the Sentry does not allow any syscall that creates or opens a file descriptor. All file descriptors must be donated to the sandbox. By disallowing open or creation of file descriptors, we eliminate entire categories of these file-based attacks.
This does not affect functionality though. For example, during startup, runsc will donate FDs the Sentry that allow for mapping STDIN/STDOUT/STDERR to the sandboxed application. Also the Gofer may donate an FD to the Sentry, allowing for direct access to some files. And most files will be remotely accessed through the Gofers, in which case no FDs are donated to the Sentry.
The Sentry itself is only allowed access to specific [whitelisted syscalls](https://github.com/google/gvisor/blob/master/runsc/boot/config.go). Without networking, the Sentry needs 53 host syscalls in order to function, and with networking, it uses an additional 15[^8]. By limiting the whitelist to only these needed syscalls, we radically reduce the amount of host OS attack surface. If any attempts are made to call something outside the whitelist, it is immediately blocked and the sandbox is killed by the Host OS.
### Sentry/Gofer Interface:
The Sentry communicates with the Gofer through a local unix domain socket (UDS) via a version of the 9P protocol[^9]. The UDS file descriptor is passed to the sandbox during initialization and all communication between the Sentry and Gofer happens via 9P. We will go more into how Gofers work in future posts.
### End Result
So, of the 350 syscalls in the Linux kernel, the Sentry needs to implement only 237 of them to support containers. At most, the Sentry only needs to call 68 of the host Linux syscalls. In other words, with gVisor, applications get the vast majority (and growing) functionality of Linux containers for only 68 possible syscalls to the Host OS. 350 syscalls to 68 is attack surface reduction.
____
![Figure 3](./figure3.png)
Figure 3: Reduction of Attack Surface of the Syscall Table. Note that the Senty's Syscall Emulation Layer keeps the Containerized Process from ever calling the Host OS.
____
## Secure-by-default
The default choice for a user should be safe. If users need to run a less secure configuration of the sandbox for the sake of performance or application compatibility, they must make the choice explicitly.
An example of this might be a networking application that is performance sensitive. Instead of using the safer, Go-based Netstack in the Sentry, the untrusted container can instead use the host Linux networking stack directly. However, this means the untrusted container will be directly interacting with the host, without the safety benefits of the sandbox. It also means that an attack could directly compromise the host through his path.
These less secure configurations are **not** the default. In fact, the user must take action to change the configuration and run in a less secure mode. Additionally, these actions make it very obvious that a less secure configuration is being used.
This can be as simple as forcing a default runtime flag option to the secure option. gVisor does this by always using its internal netstack by default. However, for certain performance sensitive applications, we allow the usage of the host OS networking stack, but it requires the user to actively set a flag[^10].
# Technology Choices
Technology choices for gVisor mainly involve things that will give us a security boundary.
At a higher level, boundaries in software might be describing a great many things. It may be discussing the boundaries between threads, boundaries between processes, boundaries between CPU privilege levels, and more.
Security boundaries are interfaces that are designed and built so that entire classes of bugs/vulnerabilities are eliminated.
For example, the Sentry and Gofers are implemented using Go. Go was chosen for a number of the features it provided. Go is a fast, statically-typed, compiled language that has efficient multi-threading support, garbage collection and a constrained set of “unsafe” operations.
Using these features enabled safe array and pointer handling. This means entire classes of vulnerabilities were eliminated, such as buffer overflows and use-after-free.
Another example is our use of very strict syscall switching to ensure that the Sentry is always the first software component that parses and interprets the calls being made by the untrusted container. Here is an instance where different platforms use different solutions, but all of them share this common trait, whether it is through the use of ptrace “a la PTRACE_ATTACH”[^11] or kvms ring0[^12].
Finally, one of the most restrictive choices was to use seccomp, to restrict the Sentry from being able to open or create a file descriptor on the host. All file I/O is required to go through Gofers. Preventing the opening or creation of file descriptions eliminates whole categories of bugs around file permissions [like this one](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-4557)[^13].
# To be continued - Part 2
In part 2 of this blog post, we will explore gVisor from an attackers point of view. We will use it as an opportunity to examine the specific strengths and weaknesses of each gVisor component.
We will also use it to introduce Googles Vulnerability Reward Program[^14], and other ways the community can contribute to help make gVisor safe, fast and stable.
<!-- Footnotes themselves at the bottom. -->
## Notes
[^1]:
[https://www.owasp.org/index.php/Security_by_Design_Principles](https://www.owasp.org/index.php/Security_by_Design_Principles)
[^2]:
[https://gvisor.dev/docs/architecture_guide](https://gvisor.dev/docs/architecture_guide/)
[^3]:
[ https://github.com/google/gvisor/blob/master/pkg/sentry/syscalls/linux/linux64_amd64.go](https://github.com/google/gvisor/blob/master/pkg/sentry/syscalls/syscalls.go)
[^4]:
Internally that is, it doesn't call to the Host OS to implement them, in fact that is explicitly disallowed, more on that in the future.
[^5]:
[https://elixir.bootlin.com/linux/latest/source/arch/x86/entry/syscalls/syscall_64.tbl#L345](https://elixir.bootlin.com/linux/latest/source/arch/x86/entry/syscalls/syscall_64.tbl#L345)
[^6]:
[https://github.com/google/gvisor/tree/master/runsc/boot/filter](https://github.com/google/gvisor/tree/master/runsc/boot/filter)
[^7]:
[https://en.wikipedia.org/wiki/Dirty_COW](https://en.wikipedia.org/wiki/Dirty_COW)
[^8]:
[ https://github.com/google/gvisor/blob/master/runsc/boot/config.go](https://github.com/google/gvisor/blob/master/runsc/boot/config.go)
[^9]:
[https://en.wikipedia.org/wiki/9P_(protocol)](https://en.wikipedia.org/wiki/9P_(protocol))
[^10]:
[ https://gvisor.dev/docs/user_guide/networking/#network-passthrough](https://gvisor.dev/docs/user_guide/networking/#network-passthrough)
[^11]:
[https://github.com/google/gvisor/blob/c7e901f47a09eaac56bd4813227edff016fa6bff/pkg/sentry/platform/ptrace/subprocess.go#L390](https://github.com/google/gvisor/blob/c7e901f47a09eaac56bd4813227edff016fa6bff/pkg/sentry/platform/ptrace/subprocess.go#L390)
[^12]:
[https://github.com/google/gvisor/blob/c7e901f47a09eaac56bd4813227edff016fa6bff/pkg/sentry/platform/ring0/kernel_amd64.go#L182](https://github.com/google/gvisor/blob/c7e901f47a09eaac56bd4813227edff016fa6bff/pkg/sentry/platform/ring0/kernel_amd64.go#L182)
[^13]:
[https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-4557](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-4557)
[^14]:
[ https://www.google.com/about/appsecurity/reward-program/index.html](https://www.google.com/about/appsecurity/reward-program/index.html)
+4
View File
@@ -0,0 +1,4 @@
---
title: "gVisor Blog"
linkTitle: "Blog"
---
+175
View File
@@ -0,0 +1,175 @@
+++
title = "Using CNI"
weight = 12
+++
This tutorial will show you how to set up networking for a gVisor sandbox using
the [Container Networking Interface (CNI)](https://github.com/containernetworking/cni).
## Install CNI Plugins
First you will need to install the CNI plugins. CNI plugins are used to set up
a network namespace that `runsc` can use with the sandbox.
Start by creating the directories for CNI plugin binaries:
```
sudo mkdir -p /opt/cni/bin
```
Download the CNI plugins:
```
wget https://github.com/containernetworking/plugins/releases/download/v0.8.3/cni-plugins-linux-amd64-v0.8.3.tgz
```
Next, unpack the plugins into the CNI binary directory:
```
sudo tar -xvf cni-plugins-linux-amd64-v0.8.3.tgz -C /opt/cni/bin/
```
## Configure CNI Plugins
This section will show you how to configure CNI plugins. This tutorial will use
the "bridge" and "loopback" plugins which will create the necessary bridge and
loopback devices in our network namespace. However, you should be able to use
any CNI compatible plugin to set up networking for gVisor sandboxes.
The bridge plugin configuration specifies the IP address subnet range for IP
addresses that will be assigned to sandboxes as well as the network routing
configuration. This tutorial will assign IP addresses from the `10.22.0.0/16`
range and allow all outbound traffic, however you can modify this configuration
to suit your use case.
Create the bridge and loopback plugin configurations:
```
sudo mkdir -p /etc/cni/net.d
sudo sh -c 'cat > /etc/cni/net.d/10-bridge.conf << EOF
{
"cniVersion": "0.4.0",
"name": "mynet",
"type": "bridge",
"bridge": "cni0",
"isGateway": true,
"ipMasq": true,
"ipam": {
"type": "host-local",
"subnet": "10.22.0.0/16",
"routes": [
{ "dst": "0.0.0.0/0" }
]
}
}
EOF'
sudo sh -c 'cat > /etc/cni/net.d/99-loopback.conf << EOF
{
"cniVersion": "0.4.0",
"name": "lo",
"type": "loopback"
}
EOF'
```
## Create a Network Namespace
For each gVisor sandbox you will create a network namespace and configure it
using CNI. First, create a random network namespace name and then create
the namespace.
The network namespace path will then be `/var/run/netns/${CNI_CONTAINERID}`.
```
export CNI_PATH=/opt/cni/bin
export CNI_CONTAINERID=$(printf '%x%x%x%x' $RANDOM $RANDOM $RANDOM $RANDOM)
export CNI_COMMAND=ADD
export CNI_NETNS=/var/run/netns/${CNI_CONTAINERID}
sudo ip netns add ${CNI_CONTAINERID}
```
Next, run the bridge and loopback plugins to apply the configuration that was
created earlier to the namespace. Each plugin outputs some JSON indicating the
results of executing hte plugin. For example, The bridge plugin's response
includes the IP address assigned to the ethernet device created in the network
namespace. Take note of the IP address for use later.
```
export CNI_IFNAME="eth0"
sudo -E /opt/cni/bin/bridge < /etc/cni/net.d/10-bridge.conf
export CNI_IFNAME="lo"
sudo -E /opt/cni/bin/loopback < /etc/cni/net.d/99-loopback.conf
```
Get the IP address assigned to our sandbox:
```
POD_IP=$(sudo ip netns exec ${CNI_CONTAINERID} ip -4 addr show eth0 | grep -oP '(?<=inet\s)\d+(\.\d+){3}')
```
## Create the OCI Bundle
Now that our network namespace is created and configured, we can create the OCI
bundle for our container. As part of the bundle's `config.json` we will specify
that the container use the network namespace that we created.
The container will run a simple python webserver that we will be able to
connect to via the IP address assigned to it via the bridge CNI plugin.
Create the bundle and root filesystem directories:
```
sudo mkdir -p bundle
cd bundle
sudo mkdir rootfs
sudo docker export $(docker create python) | sudo tar --same-owner -pxf - -C rootfs
sudo mkdir -p rootfs/var/www/html
sudo sh -c 'echo "Hello World!" > rootfs/var/www/html/index.html'
```
Next create the `config.json` specifying the network namespace.
```
sudo /usr/local/bin/runsc spec
sudo sed -i 's;"sh";"python", "-m", "http.server";' config.json
sudo sed -i "s;\"cwd\": \"/\";\"cwd\": \"/var/www/html\";" config.json
sudo sed -i "s;\"type\": \"network\";\"type\": \"network\",\n\t\t\t\t\"path\": \"/var/run/netns/${CNI_CONTAINERID}\";" config.json
```
## Run the Container
Now we can run and connect to the webserver. Run the container in gVisor. Use
the same ID used for the network namespace to be consistent:
```
sudo runsc run -detach ${CNI_CONTAINERID}
```
Connect to the server via the sandbox's IP address:
```
curl http://${POD_IP}:8000/
```
You should see the server returning `Hello World!`.
## Cleanup
After you are finished running the container, you can clean up the network
namespace .
```
sudo runsc kill ${CNI_CONTAINERID}
sudo runsc delete ${CNI_CONTAINERID}
export CNI_COMMAND=DEL
export CNI_IFNAME="lo"
sudo -E /opt/cni/bin/loopback < /etc/cni/net.d/99-loopback.conf
export CNI_IFNAME="eth0"
sudo -E /opt/cni/bin/bridge < /etc/cni/net.d/10-bridge.conf
sudo ip netns delete ${CNI_CONTAINERID}
```
+1
View File
@@ -1,5 +1,6 @@
+++
title = "WordPress with Kubernetes"
weight = 11
+++
## Deploy a WordPress site using GKE Sandbox
+3 -3
View File
@@ -23,13 +23,13 @@ gVisor supports Linux
Binaries run in gVisor should be built for the
[AMD64](https://en.wikipedia.org/wiki/X86-64) CPU architecture.
### Can I run Docker images using gVisor.
### Can I run Docker images using gVisor?
Yes. Please see the [Docker Quick Start][docker].
### Can I run Kubernetes pods using gVisor.
### Can I run Kubernetes pods using gVisor?
Yes. Please see the [Docker Quick Start][k8s].
Yes. Please see the [Kubernetes Quick Start][k8s].
### What's the security model?
+29 -39
View File
@@ -13,12 +13,21 @@ release channels. You should pick the version you'd like to install. For
experimentation, the nightly release is recommended. For production use, the
latest release is recommended.
<!--
After selecting an appropriate release channel from the options below, proceed
to the preferred installation mechanism: manual or from an `apt` repository.
-->
### HEAD
Binaries are available for every commit on the `master` branch, and are
available at the following URL:
`https://storage.googleapis.com/gvisor/releases/master/latest/runsc`
Checksums for the release binary are at:
`https://storage.googleapis.com/gvisor/releases/master/latest/runsc.sha512`
For `apt` installation, use the `master` as the `${DIST}` below.
### Nightly
@@ -37,10 +46,7 @@ Specific nightly releases can be found at:
Note that a release may not be available for every day.
<!--
To use a nightly release, use one of the above URLs for `URL` in the manual
instructions below. For `apt`, use `nightly` for `DIST` below.
For `apt` installation, use the `nightly` as the `${DIST}` below.
### Latest release
@@ -48,8 +54,7 @@ The latest official release is available at the following URL:
`https://storage.googleapis.com/gvisor/releases/release/latest`
To use the latest release, use the above URL for `URL` in the manual
instructions below. For `apt`, use `latest` for `DIST` below.
For `apt` installation, use the `release` as the `${DIST}` below.
### Specific release
@@ -59,11 +64,10 @@ A given release release is available at the following URL:
See the [releases][releases] page for information about specific releases.
For `apt` installation of a specific release, which may include point updates,
use the date of the release, e.g. `${yyyymmdd}`, as the `${DIST}` below.
This will include point updates for the release, if required. To use a specific
release, use the above URL for `URL` in the manual instructions below. For
`apt`, use `${yyyymmdd}` for `DIST` below.
> Note: only newer releases may be available as `apt` repositories.
### Point release
@@ -71,14 +75,9 @@ A given point release is available at the following URL:
`https://storage.googleapis.com/gvisor/releases/release/${yyyymmdd}.${rc}`
Note that `apt` installation of a specific point release is not supported.
Unlike the specific release above, which may include updates, this release will
not change. To use a specific point release, use the above URL for `URL` in the
manual instructions below. For apt, use `${yyyymmdd}.${rc}` for `DIST` below.
-->
<!-- Install from an `apt` repository
## Install from an `apt` repository
First, appropriate dependencies must be installed to allow `apt` to install
packages via https:
@@ -102,27 +101,21 @@ curl -fsSL https://gvisor.dev/archive.key | sudo apt-key add -
Based on the release type, you will need to substitute `${DIST}` below, using
one of:
* `nightly`: For all nightly releases.
* `latest`: For the latest release.
* `${yyyymmdd}`: For specific releases.
* `${yyyymmdd}.${rc}`: For a specific point release.
* `master`: For HEAD.
* `nightly: For nightly releases.
* `release: For the latest release.
* `${yyyymmdd}: For a specific releases (see above).
The repository for the release you wish to install should be added:
```bash
sudo add-apt-repository \
"deb https://storage.googleapis.com/gvisor/releases" \
"${DIST}" \
main
sudo add-apt-repository "deb https://storage.googleapis.com/gvisor/releases ${DIST} main"
```
For example, to install the latest official release, you can use:
```bash
sudo add-apt-repository \
"deb https://storage.googleapis.com/gvisor/releases" \
latest \
main
sudo add-apt-repository "deb https://storage.googleapis.com/gvisor/releases release main"
```
Now the runsc package can be installed:
@@ -133,10 +126,11 @@ sudo apt-get update && sudo apt-get install -y runsc
If you have Docker installed, it will be automatically configured.
-->
## Install directly
For example, the latest nightly binary can be downloaded, validated,
and placed in an appropriate location by running:
The binary URLs provided above can be used to install directly. For example, the
latest nightly binary can be downloaded, validated, and placed in an appropriate
location by running:
```bash
(
@@ -165,8 +159,4 @@ runsc install
```
[old-linux]: /docs/user_guide/networking/#gso
<!--
[latest-nightly]: https://storage.googleapis.com/gvisor/releases/nightly/latest/runsc
[latest-hash]: https://storage.googleapis.com/gvisor/releases/nightly/latest/runsc.sha512
[releases]: https://github.com/google/gvisor/releases
-->
+1 -1
View File
@@ -43,7 +43,7 @@ Finally run the container.
sudo runsc run hello
```
Next try [running gVisor using Docker](../docker/).
Next try [using CNI to set up networking](../../../tutorials/cni/) or [running gVisor using Docker](../docker/).
[oci]: https://opencontainers.org/
+32
View File
@@ -0,0 +1,32 @@
<!doctype html>
<html lang="{{ .Site.Language.Lang }}" class="no-js">
<head>
{{ partial "head.html" . }}
<title>{{ if .IsHome }}{{ .Site.Title }}{{ else }}{{ with .Title }}{{ . }} | {{ end }}{{ .Site.Title }}{{ end }}</title>
</head>
<body class="td-{{ .Kind }} td-blog">
<header>
{{ partial "navbar.html" . }}
</header>
<div class="container-fluid td-outer">
<div class="td-main">
<div class="row flex-xl-nowrap">
<div class="col-12 col-md-3 col-xl-2 td-sidebar d-print-none">
{{ partial "sidebar.html" . }}
</div>
<div class="d-none d-xl-block col-xl-2 td-toc d-print-none">&nbsp;</div>
<main class="col-12 col-md-9 col-xl-8 pl-md-5 pr-md-4" role="main">
{{ with .CurrentSection.OutputFormats.Get "rss" -}}
<a class="btn btn-lg -bg-orange td-rss-button d-none d-lg-block" href="{{ .Permalink | safeURL }}" target="_blank">
RSS <i class="fa fa-rss ml-2 "></i>
</a>
{{ end -}}
{{ block "main" . }}{{ end }}
</main>
</div>
</div>
{{ partial "footer.html" . }}
</div>
{{ partial "scripts.html" . }}
</body>
</html>
+14
View File
@@ -0,0 +1,14 @@
<div class="td-content">
<h1>{{ .Title }}</h1>
{{ with .Params.description }}<div class="lead">{{ . | markdownify }}</div>{{ end }}
<div class="td-byline mb-4">
{{ with .Params.author }}{{ T "post_byline_by" }} <b>{{ . | markdownify }}</b> |{{ end}}
<time datetime="{{ $.Date.Format "2006-01-02" }}" class="text-muted">{{ $.Date.Format $.Site.Params.time_format_blog }}</time>
</div>
{{ .Content }}
{{ if (.Site.DisqusShortname) }}
<br />
{{ partial "disqus-comment.html" . }}
<br />
{{ end }}
</div>
+24
View File
@@ -0,0 +1,24 @@
{{ if .Path }}
{{ $gh_repo := ($.Param "github_repo") }}
{{ $gh_subdir := ($.Param "github_subdir") }}
{{ $gh_project_repo := ($.Param "github_project_repo") }}
{{ if $gh_repo }}
<div class="td-page-meta ml-2 pb-1 pt-2 mb-0">
{{ $editURL := printf "%s/edit/master/content/%s" $gh_repo .Path }}
{{ if and ($gh_subdir) (.Site.IsMultiLingual) }}
{{ $editURL = printf "%s/edit/master/%s/content/%s/%s" $gh_repo $gh_subdir ($.Site.Language.Lang) $.Path }}
{{ else if .Site.IsMultiLingual }}
{{ $editURL = printf "%s/edit/master/content/%s/%s" $gh_repo ($.Site.Language.Lang) .Path }}
{{ else if $gh_subdir }}
{{ $editURL = printf "%s/edit/master/%s/content/%s" $gh_repo $gh_subdir $.Path }}
{{ end }}
{{ $issuesURL := printf "%s/issues/new?title=%s" $gh_repo (htmlEscape $.Title )}}
<a href="{{ $editURL }}" target="_blank"><i class="fa fa-edit fa-fw"></i> {{ T "post_edit_this" }}</a>
<a href="{{ $issuesURL }}" target="_blank"><i class="fab fa-github fa-fw"></i> {{ T "post_create_issue" }}</a>
{{ if $gh_project_repo }}
{{ $project_issueURL := printf "%s/issues/new" $gh_project_repo }}
<a href="{{ $project_issueURL }}" target="_blank"><i class="fas fa-tasks fa-fw"></i> {{ T "post_create_project_issue" }}</a>
{{ end }}
</div>
{{ end }}
{{ end }}
+8 -4
View File
@@ -12,8 +12,12 @@
{{ partial "hooks/body-end.html" . }}
<script type="text/javascript">
$("body.td-page,body.td-section").find("main h2,h3,h4").each(function() {
var fragment = $(this).attr('id');
$(this).append('&nbsp;<a href="#'+fragment+'" class="header-link"><i class="fas fa-link"></i></a>');
});
if (location.pathname == "/docs" || location.pathname.startsWith("/docs/")) {
$("body.td-page,body.td-section").find("main h2,h3,h4").each(function() {
var fragment = $(this).attr('id');
if (fragment !== undefined && fragment !== "") {
$(this).append('&nbsp;<a href="#'+fragment+'" class="header-link"><i class="fas fa-link"></i></a>');
}
});
}
</script>

Some files were not shown because too many files have changed in this diff Show More