update docu, add images, make tf files

This commit is contained in:
Alexander Mahr 2024-09-13 12:53:45 +02:00
parent 9ce5ca42ce
commit e9d1920689
10 changed files with 330 additions and 4 deletions

5
LICENSE Normal file
View 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
View file

@ -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
![example IAM user](./images/screenshot.aws.user.png)
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:
![generate AWS access key for user](./images/screenshot.aws.create.accesskey.png)
since they are more complicatred, disregard the suggested alternatives:
![disregard alternatives](./images/screenshot.aws.ignore.alternatives.png)
also we need no tag to be set (AWS really makes it a point to strech out and prolong simple stuff)
![no tag necessary](./images/screenshot.aws.no-tag-needed.png)
lastly get the credintials
![no tag necessary](./images/screenshot.aws.get-credentials.png)
with those credentials the above mask should have completed successfully
## Usage Part 3: the Opentofu/Terraform parts
on

View file

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

27
terraformdata/aws.tf Normal file
View 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"
}

View 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
}