Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
# Changelog

## [0.7.0] - 2026-04-17

### Added

- Add the ability to load kernel modules in user data.
- Add the ability to create template pseudo-volumes in user data, to render mustache templates to files.
- Add the ability to gzip user data.

### Changed

- Update [easyto-init](https://github.com/cloudboss/easyto-init) to `v0.4.1`, which enables all of the new features.
- Update go dependencies.

## [0.6.0] - 2026-02-03

### Added
Expand Down Expand Up @@ -85,6 +98,7 @@

Initial release

[0.7.0]: https://github.com/cloudboss/easyto/releases/tag/v0.7.0
[0.6.0]: https://github.com/cloudboss/easyto/releases/tag/v0.6.0
[0.5.0]: https://github.com/cloudboss/easyto/releases/tag/v0.5.0
[0.4.0]: https://github.com/cloudboss/easyto/releases/tag/v0.4.0
Expand Down
6 changes: 3 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ EASYTO_ASSETS_RUNTIME = easyto-assets-runtime-$(EASYTO_ASSETS_VERSION)
EASYTO_ASSETS_RUNTIME_ARCHIVE = $(EASYTO_ASSETS_RUNTIME).tar.gz
EASYTO_ASSETS_RUNTIME_URL = $(EASYTO_ASSETS_RELEASES)/$(EASYTO_ASSETS_VERSION)/$(EASYTO_ASSETS_RUNTIME_ARCHIVE)
EASYTO_INIT_RELEASES = https://github.com/cloudboss/easyto-init/releases/download
EASYTO_INIT_VERSION = v0.3.0
EASYTO_INIT_VERSION = v0.4.1
EASYTO_INIT = easyto-init-$(EASYTO_INIT_VERSION)
EASYTO_INIT_ARCHIVE = easyto-init-$(EASYTO_INIT_VERSION).tar.gz
EASYTO_INIT_URL = $(EASYTO_INIT_RELEASES)/$(EASYTO_INIT_VERSION)/$(EASYTO_INIT_ARCHIVE)
Expand Down Expand Up @@ -132,7 +132,7 @@ $(DIR_OUT)/ctr2disk: \
$(shell find pkg -type f -path '*.go' ! -path '*_test.go') \
| $(HAS_IMAGE_LOCAL) $(VAR_DIR_ET)
@docker run --rm -t \
-v $(DIR_ROOT):/code \
-v $(DIR_ROOT):/code:z \
-e OPENSSH_PRIVSEP_DIR=$(OPENSSH_PRIVSEP_DIR) \
-e OPENSSH_PRIVSEP_USER=$(OPENSSH_PRIVSEP_USER) \
-e CHRONY_USER=$(CHRONY_USER) \
Expand All @@ -155,7 +155,7 @@ $(DIR_STG_BIN)/easyto: \
$(shell find cmd/easyto -type f -path '*.go' ! -path '*_test.go') \
| $(HAS_IMAGE_LOCAL) $(VAR_DIR_ET) $(DIR_STG_BIN)/
@docker run --rm -t \
-v $(DIR_ROOT):/code \
-v $(DIR_ROOT):/code:z \
-e DIR_ET_ROOT=/$(DIR_ET) \
-e DIR_OUT=/code/$(DIR_STG_BIN) \
-e ET_VERSION=$(VERSION) \
Expand Down
60 changes: 57 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,12 +106,43 @@ Instances are created "the usual way" with the AWS console, AWS CLI, or Terrafor

### User data

The user data format is meant to be similar to a container configuration, and borrows some of its nomenclature from the Kubernetes pod spec.
The user data format is in YAML and is meant to be similar to a container configuration, and borrows some of its nomenclature from the Kubernetes pod spec.

Example:
It is written to the file `/.easyto/var/lib/user-data` on the instance for easy reference.

User data can be gzipped to reduce the size, and [easyto-init](https://github.com/cloudboss/easyto-init) will decompress it automatically.

#### Terraform

A [terraform module](https://registry.terraform.io/modules/cloudboss/easyto-user-data/aws/latest) is available to simplify creating the user data. You only need to pass variables as HCL, and it will validate the variables and render the YAML as an output.

```hcl
module "user_data" {
source = "cloudboss/easyto-user-data/aws"
version = "0.5.0"

command = ["/app/start"]
env-from = [
{
imds = {
name = "IPV4_ADDRESS"
path = "local-ipv4"
}
},
]
}

resource "aws_launch_template" "it" {
user_data = base64gzip(module.user_data.value) # gzip then base64 encode
```

#### Example

```yaml
env-from:
- imds:
name: AWS_REGION
path: placement/region
- ssm:
path: /database/abc/credentials
volumes:
Expand All @@ -120,6 +151,13 @@ volumes:
mount:
destination: /var/lib/postgresql
fs-type: ext4
- template:
content: |
My region is {{aws_region}}.
variables:
aws_region: $(AWS_REGION)
mount:
destination: /region.txt
```

See the [examples](./examples) folder for more.
Expand Down Expand Up @@ -153,6 +191,8 @@ The full specification is as follows:
> (umask 277; ${bb} cp /path/to/secret /some/other/path)
> ```

`modules`: (Optional, type _list_ of _string_, default `[]`) - Linux kernel modules to be loaded, before sysctls are set.

`replace-init`: (Optional, type _bool_, default `false`) - If `true`, `command` will replace init when executed. This may be useful if you want to run your own init process. However, easyto init will still do everything leading up to the execution of `command`, for example formatting and mounting filesystems defined in `volumes` and setting environment variables.

`security`: (Optional, type [_security_](#security-object) object, default `{}`) - Configuration of security settings.
Expand Down Expand Up @@ -257,7 +297,9 @@ The following sources are available for environment variables. Each can be speci

`ssm`: (Optional, type [_ssm-volume_](#ssm-volume-object) object, default `{}`) - Configuration of an SSM Parameter pseudo-volume.

`secrets-manager`: (Optional, type [_secrets-manager-volume_](#secrets-manager-volume-object) object) - Configuration for Secrets Manager pseudo-volume.
`secrets-manager`: (Optional, type [_secrets-manager-volume_](#secrets-manager-volume-object) object, default `{}`) - Configuration for Secrets Manager pseudo-volume.

`template`: (Optional, type [_template-volume_](#template-volume-object) object, default `{}`) - Configuration for mustache template pseudo-volume.

#### ebs-volume object

Expand Down Expand Up @@ -317,6 +359,18 @@ A Secrets Manager volume is a pseudo-volume, as the secret from Secrets Manager

`secret-id`: (Required, type _string_) - The name or ARN of the secret. If it is in another AWS account, the ARN must be used.

#### template-volume object

A template volume is used to render a mustache template to a file. This is a pseudo-volume, as content is copied as a file to the path defined in `mount.destination` one time on boot. This volume results in a single file being written, not a directory tree, the same as with the Secrets Manager volumes. The owner and group of the file defaults to `security.run-as-user-id` and `security.run-as-group-id` unless explicitly specified in the volume's `mount.user-id` and `mount.group-id`.

`content`: (Required, type _string_) - The content of the template, which uses [mustache](https://mustache.github.io/mustache.5.html) syntax.

`mount`: (Required, type [_mount_](#mount-object) object) - Configuration of the destination for the file.

`optional`: (Optional, type _bool_, default `false`) - Whether or not the template file is optional. If `true`, then failure during rendering or writing of the file will not be treated as an error.

`variables`: (Optional, type _map_ from _string_ to _any_, default `{}`) - A map of string keys with any value, used to expand the template content. The values may contain "dollar" variables resolved from `env` and `env-from` (see [variable expansion](#variable-expansion)). If `variables` is not defined, `content` will be written as a literal string with no mustache template rendering.

#### ebs-attachment object

`tags`: (Required, type [_tag-key-value_](#tag-key-value-object)) - A list of tags used to filter the EBS volume when calling `ec2:DescribeVolumes`.
Expand Down
39 changes: 26 additions & 13 deletions examples/full-user-data.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,22 @@ env:
- name: ABC
value: XYZ
env-from:
s3:
bucket: cherk-twirm-muttle
key: zomple.json
s3:
bucket: verk-bibe-boff
key: whirm/chix/jom
base64-encode: true
name: WHIRM_CHIX_JOM
ssm:
path: /thork/database/credentials
secrets-manager:
secret-id: pleam-license
name: PLEAM_LICENSE
- imds:
name: AWS_REGION
path: placement/region
- s3:
bucket: cherk-twirm-muttle
key: zomple.json
- s3:
bucket: verk-bibe-boff
key: whirm/chix/jom
base64-encode: true
name: WHIRM_CHIX_JOM
- ssm:
path: /thork/database/credentials
- secrets-manager:
secret-id: pleam-license
name: PLEAM_LICENSE
init-scripts:
- |
#!/.easyto/bin/busybox sh
Expand All @@ -31,6 +34,9 @@ init-scripts:
#!/.easyto/bin/busybox sh
bb=/.easyto/bin/busybox
${bb} echo "Running init script B"
modules:
- br_netfilter
- overlay
replace-init: false
security:
readonly-root-fs: true
Expand Down Expand Up @@ -61,4 +67,11 @@ volumes:
fs-type: btrfs
mount:
destination: /application/state
- template:
content: |
My region is {{aws_region}}.
variables:
aws_region: $(AWS_REGION)
mount:
destination: /region.txt
working-dir: /application
43 changes: 18 additions & 25 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
module github.com/cloudboss/easyto

go 1.25
go 1.25.0

require (
github.com/aws/aws-sdk-go-v2 v1.41.1
github.com/aws/aws-sdk-go-v2/config v1.32.7
github.com/aws/aws-sdk-go-v2/service/ec2 v1.285.0
github.com/diskfs/go-diskfs v1.7.0
github.com/google/go-containerregistry v0.20.7
github.com/google/go-containerregistry v0.21.5
github.com/google/uuid v1.6.0
github.com/spf13/afero v1.11.0
github.com/spf13/cobra v1.10.1
github.com/spf13/cobra v1.10.2
github.com/stretchr/testify v1.11.1
golang.org/x/sys v0.39.0
golang.org/x/sys v0.43.0
)

require (
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/anchore/go-lzo v0.1.0 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.19.7 // indirect
Expand All @@ -31,50 +30,44 @@ require (
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.13 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.41.6 // indirect
github.com/aws/smithy-go v1.24.0 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/containerd/errdefs v1.0.0 // indirect
github.com/containerd/errdefs/pkg v0.3.0 // indirect
github.com/containerd/stargz-snapshotter/estargz v0.18.1 // indirect
github.com/containerd/stargz-snapshotter/estargz v0.18.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/distribution/reference v0.6.0 // indirect
github.com/djherbis/times v1.6.0 // indirect
github.com/docker/cli v29.0.3+incompatible // indirect
github.com/docker/distribution v2.8.3+incompatible // indirect
github.com/docker/docker v28.5.2+incompatible // indirect
github.com/docker/cli v29.4.0+incompatible // indirect
github.com/docker/docker-credential-helpers v0.9.3 // indirect
github.com/docker/go-connections v0.5.0 // indirect
github.com/docker/go-connections v0.6.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/elliotwutingfeng/asciiset v0.0.0-20230602022725-51bbb787efab // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/klauspost/compress v1.18.2 // indirect
github.com/klauspost/compress v1.18.5 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/moby/docker-image-spec v1.3.1 // indirect
github.com/moby/sys/sequential v0.6.0 // indirect
github.com/moby/moby/api v1.54.1 // indirect
github.com/moby/moby/client v0.4.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.1 // indirect
github.com/pierrec/lz4/v4 v4.1.17 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pkg/xattr v0.4.12 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af // indirect
github.com/spf13/pflag v1.0.9 // indirect
github.com/sirupsen/logrus v1.9.4 // indirect
github.com/spf13/pflag v1.0.10 // indirect
github.com/ulikunitz/xz v0.5.15 // indirect
github.com/vbatts/tar-split v0.12.2 // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
go.opentelemetry.io/otel v1.39.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 // indirect
go.opentelemetry.io/otel/metric v1.39.0 // indirect
go.opentelemetry.io/otel/sdk v1.39.0 // indirect
go.opentelemetry.io/otel/sdk/metric v1.39.0 // indirect
go.opentelemetry.io/otel/trace v1.39.0 // indirect
go.opentelemetry.io/proto/otlp v1.9.0 // indirect
golang.org/x/sync v0.18.0 // indirect
go.opentelemetry.io/otel v1.43.0 // indirect
go.opentelemetry.io/otel/metric v1.43.0 // indirect
go.opentelemetry.io/otel/sdk v1.43.0 // indirect
go.opentelemetry.io/otel/sdk/metric v1.43.0 // indirect
go.opentelemetry.io/otel/trace v1.43.0 // indirect
golang.org/x/sync v0.20.0 // indirect
golang.org/x/text v0.28.0 // indirect
google.golang.org/protobuf v1.36.10 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
Loading
Loading