update docu, add images, make tf files
This commit is contained in:
parent
9ce5ca42ce
commit
e9d1920689
10 changed files with 330 additions and 4 deletions
5
LICENSE
Normal file
5
LICENSE
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
(C) 2024 by Alexander Mahr Berlin
|
||||||
|
Licensed for non-commercial use by people.
|
||||||
|
Not licensed for big commercial actors or similar
|
||||||
|
No warranty of any kind. use at own risk
|
||||||
|
|
178
README.md
178
README.md
|
@ -1,2 +1,178 @@
|
||||||
# compose spec based containerized setup for tf/opentofu
|
# An Example Terraform(Opentofu) setup "packed" as a (docker)compose application
|
||||||
|
|
||||||
|
This repo contains a [`compose.yml`](./compose.yml) file. With such a `compose.yml` which
|
||||||
|
sometimes can be named also `docker-compose.yml` we setup an application, defined by services
|
||||||
|
|
||||||
|
```
|
||||||
|
# this is exampoel compose.yml content
|
||||||
|
services:
|
||||||
|
a_service:
|
||||||
|
image: name/of-container-image:tag
|
||||||
|
another_service:
|
||||||
|
image: name/of-container-image:tag
|
||||||
|
[...]
|
||||||
|
```
|
||||||
|
|
||||||
|
The compose.yml in this repo has only a single service that is the container/service "terraform"
|
||||||
|
|
||||||
|
## Usage Part 1: the `docker compose` part
|
||||||
|
|
||||||
|
### Requirements
|
||||||
|
After having `docker compose` installed (it should be a versoin 2.XX, given version 1 is outdated)
|
||||||
|
which can be checked via:
|
||||||
|
```
|
||||||
|
#> docker compose version
|
||||||
|
Docker Compose version 2.29.2
|
||||||
|
```
|
||||||
|
|
||||||
|
### Build the application
|
||||||
|
A first step is to `docker compose` `build` the application
|
||||||
|
|
||||||
|
```
|
||||||
|
#> docker compose build
|
||||||
|
```
|
||||||
|
|
||||||
|
This will build the image for the container. The service terraform inside `compose.yml`
|
||||||
|
uses the this information to have an inline Dockerfile/recipe:
|
||||||
|
|
||||||
|
```
|
||||||
|
services:
|
||||||
|
terraform:
|
||||||
|
hostname: container-for-tf
|
||||||
|
volumes:
|
||||||
|
- ./terraformdata:/terraformdata
|
||||||
|
build:
|
||||||
|
dockerfile_inline: |
|
||||||
|
FROM alpine:latest
|
||||||
|
RUN apk update
|
||||||
|
RUN apk add aws-cli-bash-completion aws-cli aws-cli-doc bash bash-completion
|
||||||
|
RUN apk add man-db man-pages
|
||||||
|
RUN apk add opentofu
|
||||||
|
RUN apk add vim jq less
|
||||||
|
RUN <<EOF
|
||||||
|
cat >> /etc/bash/bashrc <<BASHRC
|
||||||
|
complete -C '$(which aws_completer)' aws
|
||||||
|
tofu() {
|
||||||
|
while ! aws sts get-caller-identity
|
||||||
|
do
|
||||||
|
echo "no valid aws credentials setup, running 'aws configure'"
|
||||||
|
aws configure
|
||||||
|
done
|
||||||
|
unset tofu
|
||||||
|
command tofu "$@"
|
||||||
|
}
|
||||||
|
alias terraform='tofu'
|
||||||
|
alias terra='tofu'
|
||||||
|
EOF
|
||||||
|
ENTRYPOINT ["/bin/bash"]
|
||||||
|
WORKDIR /terraformdata
|
||||||
|
```
|
||||||
|
|
||||||
|
### Use/Run the terraform/service to do opentofu/terraform stuff
|
||||||
|
|
||||||
|
After the compose application terrafrom was build one can run it.
|
||||||
|
(to be fair, if having skipped the previous `docker compose build` step it would be automaticly
|
||||||
|
build when running anyways, as clearly the contaner image is required to run the container service
|
||||||
|
hence `docker compose run -it terraform` would automatically build it with the inline `Dockerfile`
|
||||||
|
information in the `services.terraform.build.dockerfile_inline` information.
|
||||||
|
|
||||||
|
To now run the terraform service use:
|
||||||
|
```
|
||||||
|
docer compose run -it terraform
|
||||||
|
```
|
||||||
|
|
||||||
|
this will drop the user into a shell inside the container with the following utilities setup:
|
||||||
|
* `aws` (the Amazon web services aws command line tool)
|
||||||
|
* `jq` (a tool to handle JSON on the command line)
|
||||||
|
* `less` (less command)
|
||||||
|
* `vim` (to have an editor if needed inside the container)
|
||||||
|
* a feels like `bash` shell and completion for the `aws` command line (given
|
||||||
|
* `man` manual pages
|
||||||
|
* `tofu` (aliased also to be run as `terra` and `terraform`), the opentofu tool
|
||||||
|
|
||||||
|
## Usage Part 2: the AWS part
|
||||||
|
|
||||||
|
Once dropped into the shell in the container of `compose.yml`'s terraform service.
|
||||||
|
the main command one can interact with is `tofu`.
|
||||||
|
|
||||||
|
The first stell should be to run just `tofu` which will check if the container
|
||||||
|
is already setup to interact with an AWS account (which if it is a fresh container
|
||||||
|
it will most likely not)
|
||||||
|
|
||||||
|
this will happen:
|
||||||
|
```
|
||||||
|
container-for-tf:/terraformdata# tofu
|
||||||
|
|
||||||
|
Unable to locate credentials. You can configure credentials by running "aws configure".
|
||||||
|
no valid aws credentials setup, running 'aws configure'
|
||||||
|
AWS Access Key ID [None]: AK..............
|
||||||
|
AWS Secret Access Key [None]: hereYourAWSSecretAccessKeyPasted
|
||||||
|
Default region name [None]: eu-central-1
|
||||||
|
Default output format [None]:
|
||||||
|
{
|
||||||
|
"UserId": "AID........",
|
||||||
|
"Account": ".........",
|
||||||
|
"Arn": "arn:aws:iam::.......:user/user....."
|
||||||
|
}
|
||||||
|
Usage: tofu [global options] <subcommand> [args]
|
||||||
|
|
||||||
|
The available commands for execution are listed below.
|
||||||
|
The primary workflow commands are given first, followed by
|
||||||
|
less common or more advanced commands.
|
||||||
|
|
||||||
|
Main commands:
|
||||||
|
init Prepare your working directory for other commands
|
||||||
|
validate Check whether the configuration is valid
|
||||||
|
plan Show changes required by the current configuration
|
||||||
|
[...]
|
||||||
|
```
|
||||||
|
|
||||||
|
as is visible in the above this required to specify a amazon IAM user via
|
||||||
|
the crediatals of
|
||||||
|
a) AWS Access Key ID (i.e. alike an ID/username)
|
||||||
|
b) AWS Secret Access Key (i.e. kind of a password, indeeed a base64 encoded key)
|
||||||
|
|
||||||
|
hence to successfuly go through the dialog on needs to setup the users
|
||||||
|
this can be done in the [amazon web gui for IAM](https://us-east-1.console.aws.amazon.com/iam/home?region=eu-west-1#/users)
|
||||||
|
IAM is the user service/permissions part of AWS.
|
||||||
|
|
||||||
|
It makes much sense to setup a new user that is dedicated to EC2 (aws instances).
|
||||||
|
The process to do so is somewhat challenging because of the sheer number of stuff
|
||||||
|
that AWS has stuffed into AWS such as
|
||||||
|
|
||||||
|
* users
|
||||||
|
* roles
|
||||||
|
* policies
|
||||||
|
* permissions
|
||||||
|
* identify provides......
|
||||||
|
|
||||||
|
indeed we need only users. Such a user should have those Permission Policies set
|
||||||
|
* AmazonEC2FullAccess (since we want to have the use be able to do all EC2 stuff)
|
||||||
|
* a "inline persmission" allowing the read of STS -> get-caller-identiy (required to use the `aws` cli tool)
|
||||||
|
|
||||||
|
This is an exmaple user screenshoted
|
||||||
|

|
||||||
|
|
||||||
|
Once the user is created it is required to generate the credentials to be used in the dialog above.
|
||||||
|
This can be done in the here:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
since they are more complicatred, disregard the suggested alternatives:
|
||||||
|

|
||||||
|
|
||||||
|
also we need no tag to be set (AWS really makes it a point to strech out and prolong simple stuff)
|
||||||
|

|
||||||
|
|
||||||
|
lastly get the credintials
|
||||||
|

|
||||||
|
|
||||||
|
with those credentials the above mask should have completed successfully
|
||||||
|
|
||||||
|
|
||||||
|
## Usage Part 3: the Opentofu/Terraform parts
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
on
|
||||||
|
|
22
compose.yml
22
compose.yml
|
@ -1,14 +1,30 @@
|
||||||
services:
|
services:
|
||||||
terraform:
|
terraform:
|
||||||
|
hostname: container-for-tf
|
||||||
volumes:
|
volumes:
|
||||||
- ./terraformdata:/terraformdata
|
- ./terraformdata:/terraformdata
|
||||||
build:
|
build:
|
||||||
dockerfile_inline: |
|
dockerfile_inline: |
|
||||||
FROM alpine:latest
|
FROM alpine:latest
|
||||||
RUN apk update
|
RUN apk update
|
||||||
RUN apk add aws-cli-bash-completion aws-cli bash bash-completion
|
RUN apk add aws-cli-bash-completion aws-cli aws-cli-doc bash bash-completion
|
||||||
|
RUN apk add man-db man-pages
|
||||||
RUN apk add opentofu
|
RUN apk add opentofu
|
||||||
RUN echo "complete -C '$(which aws_completer)' aws" >> /etc/bash/bashrc
|
RUN apk add vim jq less
|
||||||
|
RUN <<EOF
|
||||||
|
cat >> /etc/bash/bashrc <<BASHRC
|
||||||
|
complete -C '$(which aws_completer)' aws
|
||||||
|
tofu() {
|
||||||
|
while ! aws sts get-caller-identity
|
||||||
|
do
|
||||||
|
echo "no valid aws credentials setup, running 'aws configure'"
|
||||||
|
aws configure
|
||||||
|
done
|
||||||
|
unset tofu
|
||||||
|
command tofu "$@"
|
||||||
|
}
|
||||||
|
alias terraform='tofu'
|
||||||
|
alias terra='tofu'
|
||||||
|
EOF
|
||||||
ENTRYPOINT ["/bin/bash"]
|
ENTRYPOINT ["/bin/bash"]
|
||||||
WORKDIR /terraformdata
|
WORKDIR /terraformdata
|
||||||
|
|
||||||
|
|
BIN
images/screenshot.aws.create.accesskey.png
Normal file
BIN
images/screenshot.aws.create.accesskey.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 105 KiB |
BIN
images/screenshot.aws.get-credentials.png
Normal file
BIN
images/screenshot.aws.get-credentials.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 64 KiB |
BIN
images/screenshot.aws.ignore.alternatives.png
Normal file
BIN
images/screenshot.aws.ignore.alternatives.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 136 KiB |
BIN
images/screenshot.aws.no-tag-needed.png
Normal file
BIN
images/screenshot.aws.no-tag-needed.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 44 KiB |
BIN
images/screenshot.aws.user.png
Normal file
BIN
images/screenshot.aws.user.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 98 KiB |
27
terraformdata/aws.tf
Normal file
27
terraformdata/aws.tf
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
# this is a terraform file "*.tf"
|
||||||
|
# lines starting with # are comments
|
||||||
|
# terraform is now "commercial/proprietary" hence we go with drop replacement opentofu (free software)
|
||||||
|
# Opentofu/Terraform work by writing "resources" that one wants to be created
|
||||||
|
# those resources can then
|
||||||
|
# a) be easily planned + applyed (i.e. created)
|
||||||
|
# # tofu plan -out ourplan
|
||||||
|
# # tofu apply outplan
|
||||||
|
# b) be as easily removed/deletet/destroyed
|
||||||
|
# # tofu destroy
|
||||||
|
#
|
||||||
|
# in this file we setup the "modules" and "terraform" stuff
|
||||||
|
# so that aws resources can be managed via terraform
|
||||||
|
|
||||||
|
terraform {
|
||||||
|
required_providers {
|
||||||
|
aws = {
|
||||||
|
source = "hashicorp/aws"
|
||||||
|
version = "~> 4.16"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
required_version = ">= 1.2.0"
|
||||||
|
}
|
||||||
|
|
||||||
|
provider "aws" {
|
||||||
|
region = "eu-central-1"
|
||||||
|
}
|
102
terraformdata/ec2-instance.tf
Normal file
102
terraformdata/ec2-instance.tf
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
# this is a terraform file "*.tf"
|
||||||
|
# lines starting with # are comments
|
||||||
|
# terraform is now "commercial/proprietary" hence we go with drop replacement opentofu (free software)
|
||||||
|
# Opentofu/Terraform work by writing "resources" that one wants to be created
|
||||||
|
# those resources can then
|
||||||
|
# a) be easily planned + applyed (i.e. created)
|
||||||
|
# # tofu plan -out ourplan
|
||||||
|
# # tofu apply outplan
|
||||||
|
# b) be as easily removed/deletet/destroyed
|
||||||
|
# # tofu destroy
|
||||||
|
#
|
||||||
|
# now the list of resources we would need if we make an EC2 instance
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# RESOURCE 1) an "aws_key_pair", as we now it suffices to provide our public ssh-key
|
||||||
|
# as clearly we are capable of localy having a ssh-keypair setup
|
||||||
|
# or more likely even we have an ssh-agent already setup that has several
|
||||||
|
# of our ssh-keys already there. hence
|
||||||
|
# we use `ssh-add -L` command ot get the public part
|
||||||
|
resource "aws_key_pair" "our_public_ssh_key" {
|
||||||
|
|
||||||
|
# the name for the resource
|
||||||
|
key_name = "our_public_ssh_key"
|
||||||
|
|
||||||
|
# this part we fill in here:
|
||||||
|
public_key = "ssh-rsa AAAAB.............(fill in here the result of `ssh-add -L`"
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# RESOURCE 2) an "aws_security_group" is like the rules what network connections are
|
||||||
|
# allowed for the "aws_instance" we use this resource with
|
||||||
|
resource "aws_security_group" "our_security_group" {
|
||||||
|
|
||||||
|
# rules about incoming network connections to the instance
|
||||||
|
ingress {
|
||||||
|
# allowed port(s) starting form this port number
|
||||||
|
from_port = 22
|
||||||
|
# allowed ports(s) up to this port number (here is is only SSH port 22)
|
||||||
|
to_port = 22
|
||||||
|
# the allowed protocol (i.e we allow TCP, hence prob. we are unable to ICMP ping the box)
|
||||||
|
protocol = "tcp"
|
||||||
|
# the allowed ip origins this rule applies to (0.0.0.0/0) is all ipv4 addresses "everyone"
|
||||||
|
cidr_blocks = ["0.0.0.0/0"]
|
||||||
|
}
|
||||||
|
|
||||||
|
# same can be done for limiting outgoing connections that come from
|
||||||
|
# the associated instanc
|
||||||
|
egress {
|
||||||
|
# same as above, just for outgoing
|
||||||
|
from_port = 0
|
||||||
|
to_port = 0
|
||||||
|
protocol = "-1"
|
||||||
|
cidr_blocks = ["0.0.0.0/0"]
|
||||||
|
ipv6_cidr_blocks = ["::/0"]
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# RESOURCE 3) the "aws_instance" this is what sets up 1xinstance
|
||||||
|
#
|
||||||
|
resource "aws_instance" "ubuntu-on-t4g-nano" {
|
||||||
|
|
||||||
|
# First thing to select it the "image" (amazon machine image)
|
||||||
|
# that we want to use with our instance. (via `aws ec2 decribe-images` you will
|
||||||
|
# get a large JSON back with all images existing)
|
||||||
|
# the image we use is
|
||||||
|
# "ami-07034695835d8f3bd" is arm64 amazon ubuntu 22.04 minimal
|
||||||
|
# because ubuntu is good for testing + arm64 is the architecture of "t4g.nano" instance_type
|
||||||
|
ami = "ami-07034695835d8f3bd"
|
||||||
|
|
||||||
|
# We select the type of instance we want
|
||||||
|
# t4g.nano is cheapest hourly rate at 0.0048 USD per hour or 3.45 USD per month
|
||||||
|
# on demand pricing
|
||||||
|
# this instance type is 0.5GiB memory + 2 vCPU,
|
||||||
|
instance_type = "t4g.nano"
|
||||||
|
|
||||||
|
# clearly we want to be able to access it via ssh, hence our key is reverenced
|
||||||
|
# the one we created as "RESOURCE 1)
|
||||||
|
key_name = "our_public_ssh_key"
|
||||||
|
|
||||||
|
# Also we now use the "aws_security_group" of RESOURCE 2) above
|
||||||
|
vpc_security_group_ids = [aws_security_group.our_security_group.id]
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# OUTPUT
|
||||||
|
# yes this is not a resource, but an output it allows us that
|
||||||
|
# the `tofu apply ourplan` command prints directly some resulting
|
||||||
|
# info (in our case the ipv4 of the machine (needed for ssh)
|
||||||
|
output "instance_ip" {
|
||||||
|
description = "The public ip for ssh access"
|
||||||
|
value = aws_instance.ubuntu-on-t4g-nano.public_ip
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue