Docker Targets¶
Each target must reside on its own directory under Dockerfiles/. Each target folder has the following structure
autoregister.ymlAn ansible playbook that is executed during the docker image build. Most of the times you dont have to modify this file.DockerfileThis includes your standardDockerfileinstructions in order to build your target imageentrypoint.shThe script executed when the container startsREADME.mdA readme explaining the target, solution and other details (this is empty but you are advised to keep detailed records here as it will become harder to recall details the more targets you got)variables.ymlThe variables used by theautoregister.ymlplaybook to do its job
You can use the existing Dockerfiles/example to get started or create your own.
Edit the file Dockerfiles/example/variables.yml and start by modifying the basic information.
ansible_host: 10.0.160.3
DOCKER: localhost
mac: "de:ad:be:ef:c0:ff:ee"
hostname: example
fqdn: example.echocity-f.com
rootable: 0 # 1 for yes
difficulty: 3
#scheduled_at: "YYYY-mm-dd HH:MM:SS"
The meaning and use of the variables is:
ansible_hostthe IP address that the container will be assigned. During development (eg while testingdocker build) the default IP is usually one from the172.17.0.0/24subnetDOCKERThe docker host that will run this container (egdockerd.example.net)macA valid and unique mac address. A nice trick to generate mac addresses for your hosts is to run something like the following
printf "02:42:%.2x:%.2x:%.2x:%.2x\n" $(echo "IP_ADDRESS_OF_TARGET"|sed -e 's/\./ /g')
hostnameandFQDNfor the target. The hostname is also used as the container name when startedrootableWether or not this target can be rooted or not0=non-rootableand1=rootabledifficultyA difficulty score for the target between 0 and 5. With 0 being the easiest and 5 harderscheduled_atUncomment to schedule this target to power up at a specific date and time
After the basic information, container specific details are included.
container:
name: "{{hostname}}"
hostname: "{{fqdn}}"
build: "example" # The current folder name
image: "example" # The current folder name
state: "started"
mac_address: "{{mac}}"
purge_networks: "yes"
# tag: "v0.1"
# buildargs:
# var_name: var_value
env:
ETSCTF_FLAG: "ETSCTF_{{ETSCTF_ENV_FLAG}}"
dns_servers:
- "10.0.0.254"
networks:
- { name: AAnet, ipv4_address: "{{ansible_host}}" }
volumes: []
These details you need to modify include
buildandimageThe folder that we are going to build the image from and the name that the intermediate image will have. When the images are pushed to a registry the name changes tohostnametagA version/build tag. If no tag is defined then the default tag islatestbuildargsKey/Value pair of variables needed to build the container. More details about this can be found at docker –build-argenvKey/Value environment variables defined upon starting a container. More details about the docker--envcan be found at docker env variablesdns_serversA list of dns servers that the container will use for name resolutionnetworksThe network this container will be attached. This is the same name as the one we created on our docker server (egAAnet)volumesA list of volumes to be mapped when the container starts
After that we can configure the core flags for /root, env, /etc/shadow and /etc/passsw
ETSCTF_ROOT_FLAG: ""
ETSCTF_ENV_FLAG: ""
ETSCTF_SHADOW_FLAG: ""
ETSCTF_PASSWD_FLAG: ""
We prefer to use random md5 hashes for these flags, but you can use whatever you like. The way we generate them is by using the password generator pwgen and piping its output to md5sum like so
pwgen|md5sum
One you have created all your docker targets prepare their hosts file we did with the dockers servers.
echo "[targets]"> inventories/targets/hosts
echo "example.fqdn.com">>inventories/targets/hosts
And add links from the variables.yml file of each container into the
targets/host_vars like the following example
ln -s ../../../Dockerfiles/example/variables.yml inventories/targets/host_vars/example.fqdn.com.yml
NOTE: Ansible tries to access the example.fqdn.com.yml file relative to the inventories/targets/host_vars folder. You need to include the ../../../ part when creating the symbolic link for it to be able to find the variables.
Alternatively you can generate both hosts and their corresponding host_vars by running the following from the ansible folder.
INVENTORY="targets"
echo "[$INVENTORY]">inventories/$INVENTORY/hosts
for i in Dockerfiles/*;do
fqdn=$(grep ^fqdn $i/variables.yml|awk '{print $2}')
ln -fs ../../../$i/variables.yml inventories/$INVENTORY/host_vars/${fqdn}.yml
echo -e "${fqdn}\t\t\t# "$(basename $i)>>inventories/$INVENTORY/hosts
done
In order to build the target images
ansible-playbook playbooks/build-images.yml -i inventories/targets --extra-vars "BUILDER=localhost" --extra-vars "DOCKER_REGISTRY=myregistry:5000" --extra-vars "DOCKER_REPOSITORY=targets"
Feed the data to the backend
ansible-playbook playbooks/feed-targets.yml -i inventories/targets -e '{"mui":{"URL": "http://127.0.0.1:8080"}}'
You can also create a file at inventories/targets/group_vars/all.yml for the targets to include all those extra-vars details and not having to type them again
DOCKER_REGISTRY: "myregistry:5000"
DOCKER_REPOSITORY: "targets"
TOKEN: MyMUIToken
mui:
URL: "{{MUI_URL|default('http://localhost:8080')}}"
Alternative build¶
You can also use the playbooks/build-squash.yml to build images with squashed layers. This however requires to add the option "experimental": true, to /etc/docker/daemon.json like so
{
"experimental": true,
"insecure-registries":["myregistry:5555"]
}
Once done restart the docker daemon for the changes to take effect and try to build your image
ansible-playbook playbooks/build-squash.yml -i inventories/targets
This playbook provides a few tags to ease in managing single tasks, such as * build: Build image * push: Push image to registry * rmi: Remove the image from local images
These tags can be used to perform a specific task or to skip some ie
ansible-playbook playbooks/build-squash.yml -i inventories/targets --skip-tags push,rmi