Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

First draft of devcontainers #1520

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ images: []
weight: 020
---

Chaingaurd's [*assumable identities*](/chainguard/chainguard-enforce/iam-groups/assumable-ids/) are identities that can be assumed by external applications or workflows in order to perform certain tasks that would otherwise have to be done by a human.
Chainguard's [*assumable identities*](/chainguard/chainguard-enforce/iam-groups/assumable-ids/) are identities that can be assumed by external applications or workflows in order to perform certain tasks that would otherwise have to be done by a human.

This procedural tutorial outlines how to create an identity using Terraform, and then how to update a Bitbucket pipeline so that it can assume the identity and interact with Chainguard resources.

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
---
title: "Getting Started with the Chainguard Images as Dev Containers"
type: "article"
linktitle: "Dev Containers"
aliases:
- /chainguard/chainguard-images/getting-started/devcontainers
description: "Tutorial on using Chainguard Images as Dev Containers"
date: 2024-04-15T11:07:52+02:00
lastmod: 2024-04-15T11:07:52+02:00
tags: ["Chainguard Images", "Products"]
draft: false
images: []
menu:
docs:
parent: "getting-started"
weight: 610
toc: true
---
# Dev Containers with Chainguard Images
The images based on Wolfi and maintained by Chainguard provide distroless images that can be used as Dev Containers with a few changes.

Chainguard offers minimal runtime images designed for running production workloads, and development images that contain a shell and some development tooling. But both development and production images are slimmed down and updated regularly to be CVE free.

Whilst it is obvious why production images should be secure, you may be wondering "why do I worry if my dev env gets hacked, there is no data in it?". The answer is simple. Your code goes into the production environment. If you have been hacked during development, then perhaps the hackers code goes into production as well. This is a "supply chain" attack.

Hopefully you would notice a chunk of rogue code being added to your source. What you might not notice is a change to a dependency, that looks like an update, but is actually malware using a typo-squat. For example updating `color:1.1` to `co1or:1.2`. Especially in a huge list of dependency updates that you maybe don't even check. As long as your app works!

We'll go through the changes you need to use a Chainguard development image as a Dev Container in VS Code.

If you would like to build and use a Dev Container you will need a compatible Integrated Development Environment (IDE) or other tool. Here is list of [supported tools](https://containers.dev/supporting).

To keep it simple, this guide is written for [Visual Studio Code (VS Code)](https://code.visualstudio.com/)

You will also need a Docker server to connect to. Usually a local install of Docker Desktop, but full instructions can be found [here](https://code.visualstudio.com/docs/devcontainers/containers)


{{< details "What is distroless" >}}
{{< blurb/distroless >}}
{{< /details >}}

{{< details "What is Wolfi" >}}
{{< blurb/wolfi >}}
{{< /details >}}

{{< details "Chainguard Images" >}}
{{< blurb/images >}}
{{< /details >}}

## Simple setup

You can get see a simple example if you take the content of the `chainguard-go-devcontainer` directory in our demo repository and push it to the root of an empty repository.

For example:
``` sh
git clone https://github.com/chainguard-dev/edu-images-demos.git
cd edu-images-demos/chainguard-go-devcontainer
git init .
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you feel very strongly about having the user initialize a repo on their remote GitHub? I think the tutorial runs fine with just the first two Git lines here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, I think it's got 2 jobs. The first part is a "Do this and it works" intro to Dev Containers. (Using Go)

The second part is more trying to explain the changes you need to make for using our images in a Dev Container. (Using Python). Root/nonroot is an entire topic in itself!

The different languages are used to avoid the inevitable "Does this work for other languages" question if the whole thing used Go. I did consider doing a 3rd section with another language but it would be mostly repeating the previous stuff with replacing Python with "whatever" and a different command to install dependencies. Maybe a different set of plugins in VSCode. It doesn't really add much. (Maybe replace all "python" with "node" and "pip" with "npm". Otherwise it looks nearly the same)

Pushing the folder back to a new repo means it works with GitHub Codespaces and you get prompted to "Reopen in Devcontainer" when you open the repo in VS Code. With it in a subdirectory, I don't think it ever prompts you. But it did say it's written for VS Code, so could maybe just make sure the commentary warns people that for Codespaces they'd have to move the folder to the root of their repo.

git add * .??*
git commit -am "Initial Commit"
git remote add origin https://github.com/<my github profile>/empty.git
git push -fu origin main
```

If you open VS Code on this directory now, you will be prompted to open the project in a Dev Container.

![VS Code window showing the prompt to reopen project in Dev Container](vscode-1.png)

If you go ahead and reopen in a Dev Container it may take a minute or so to build the first time you use it. Open a terminal and you can run the sample project, even if you don't have Go installed on your local machine.

![VS Code window with a Go program in the editor being run in the Terminal](vscode-2.png)

If you run a webserver in your Dev Container you will be asked if you want to open the port in a local browser. Exactly as if you were running in a local container.

![VS Code running helloserver and prompting the user to Open in Browser](vscode-3.png)


## Building a Dev Container in other languages

If you want to develop in languages other than Go, you'll need to use a different base image. To do that, you need some understanding of what the Dev Container does.

To understand what we're doing, you'll need a basic knowledge of `Dockerfile`, Docker builds, JSON, and probably will need to know how your language installs libraries or packages.

NB There are a couple of different ways to set things up, this particular setup is not required as long as the various requirements are met. The example project uses a `Dockerfile` and `devcontainer.json` in a `.devcontainer` directory. This has the advantage of keeping the "real" code separate from the Dev Container config.

Lets walk through an example for Python

### Create the skeleton structure
Assuming you're starting from a project with no Dev Container you'll want to create the files/folders you need.
```
mkdir .devcontainer
touch .devcontainer/{Dockerfile,devcontainer.json}
```

### Create Dev Container config file
Add this to the `devcontainer.json` config file:
``` json
{
"name": "my-devcontainer",
"build": {
"dockerfile": "Dockerfile",
"args": {}
},
"customizations": {
"vscode": {
"extensions": [ "ms-python.python" ]
}
},
"postCreateCommand": "pip install -r requirements.txt",
"remoteUser": "nonroot"
}
```

Because this is for a Python app, we are installing the VS Code python extension and using `pip` to install project dependencies.

The postCreateCommand runs in the root of your project after it has been cloned into the Container. If you don't have a `requirements.txt` file with your project the command will fail and you will need to remove the command to use the Dev Container.

### Find a base image and customize the Dockerfile
Chainguard offer a wide range of images for different languages and ecosystems. To search, use [the images directory](https://images.chainguard.dev/directory?category=languages).

For this example, we need Python. Many Chainguard images are available at Docker Hub now meaning we can set the `FROM` line in the `Dockerfile` to

```dockerfile
FROM chainguard/python:latest-dev
```
It is important to use the latest-dev version of the image to get tools like apk (the package manager) and a shell.

Depending on the image, you may need a line:
```dockerfile
USER root
```

So that the next commands run as root instead of the unprivileged user. You can check by running your image locally and using the id command
``` shell
docker run -it --entrypoint id chainguard/python:latest-dev
uid=65532(nonroot) gid=65532(nonroot) groups=65532(nonroot)
docker run -it --entrypoint id chainguard/go:latest-dev
uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)
```

Python, you need `USER root`. Go, you are already root.

Next, you need to install the posix utils from which Dev Containers uses the `getent` command. And then update the library links with `ldconfig`.
``` dockerfile
RUN apk update && apk add posix-libc-utils && ldconfig
```

The `ldconfig` and `getent` are needed to allow the container start scripts from VS Code to run. They may already be run in some base images.

If your language needs any other packages installing as `root` now is the time to add them.

Otherwise, continue the Dockerfile as nonroot and install any packages the language or VSCode extension might need. The Python plugin uses `pylance` and `debugpy`. (You don't have to install them now, the plugin can install them later.)

``` dockerfile
USER nonroot
RUN pip install pylance debugpy
```

NB Do NOT install packages your project needs here. The image build happens before the source code is cloned. So you'd need to somehow duplicate listing your dependencies into this file as
well as wherever they are already listed. Instead, use the `postCreateCommand`.

If you save those 2 files into an existing python repository you should then be able to reopen in a Dev Container.

### Customising the image
You can add more customisation to the `Dockerfile`. But sometimes you may find you need to run commands as root. The stripped down, distroless, images do not include sudo and there is no root password to use.

To add sudo, you can add this to the `Dockerfile` in the section running as `root`
``` dockerfile
RUN apk add sudo-rs shadow && echo "nonroot ALL = (ALL:ALL) NOPASSWD:ALL" >> /etc/sudoers && echo y | pwck -q || true
```

## GitHub Codespaces

CodeSpaces support Dev Containers. But at present they only work when the config is stored at the root directory (This is why our demo repo can't be loaded with Codespaces).

## SSH/GPG keys
The IDE should pass your keys through to the Dev Container using ssh-agent and gpg-agent. However you may need to install gpg/ssh tools inside the container.

See the VS Code page on [advanced usage](https://code.visualstudio.com/remote/advancedcontainers/sharing-git-credentials) for more information.

# Conclusion
You should now have a development environment that does not need packages installing on your local machine and that will run the same for anyone editing your project.

You may want to add things like linting rules or other components to your Dev Container config. The [VS Code website](https://code.visualstudio.com/docs/devcontainers/containers) has a lot more information about Dev Containers in general.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ toc: true

[Common vulnerabilities and exposures](/software-security/cves/cve-intro/#what-is-a-cve), often referred to as "CVEs", are an increasing concern for both developers and consumers of software. A new CVE that appears in a widely-used application or a vulnerability scan with a large number of positive results would naturally be worrisome for developers, CISOs, and end users alike.

Chances are, your software has already been impacted by a CVE. It's likely there are active CVEs in software you are using. After all, there are software vulnerabilities currently in existence that haven't even been discovered (known as [zero-day vulnerabilities](/software-security/glossary/#zero-day)). With that said, this conceptual article aims to highlight a few practices and strategies you and your team can use to reduce the risk of CVEs on your software. It also includes a section on [tools recommended by Chaingaurd](#recommended-tools) that can help to reduce your attack surface area and minimize your risk of CVEs.
Chances are, your software has already been impacted by a CVE. It's likely there are active CVEs in software you are using. After all, there are software vulnerabilities currently in existence that haven't even been discovered (known as [zero-day vulnerabilities](/software-security/glossary/#zero-day)). With that said, this conceptual article aims to highlight a few practices and strategies you and your team can use to reduce the risk of CVEs on your software. It also includes a section on [tools recommended by Chainguard](#recommended-tools) that can help to reduce your attack surface area and minimize your risk of CVEs.


## Understanding potential risks
Expand Down