diff --git a/Makefile b/Makefile
index 5f47c8274..a6cc5c8a4 100644
--- a/Makefile
+++ b/Makefile
@@ -22,6 +22,7 @@ LINTER_CONFIG       := .golangci.yaml
 
 # docker
 DOCKER_MAKE_TARGET  := build
+DOCKER_CMD_FLAGS    :=
 
 # docker image options
 DOCKER_REGISTRY     ?= quay.io
@@ -32,6 +33,13 @@ DOCKER_IMAGE_TAG    ?= latest
 DOCKER_IMAGE        ?= $(DOCKER_REGISTRY)/$(DOCKER_IMAGE_PREFIX)/$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG)
 DOCKER_TARGET_STAGE ?= release
 PUBLISH             ?= false
+# use this variables to override base images in internal build process
+ifneq ($(strip $(DOCKER_BASE_GO_IMAGE)),)
+DOCKER_CMD_FLAGS    += --build-arg GO_IMAGE=$(strip $(DOCKER_BASE_GO_IMAGE))
+endif
+ifneq ($(strip $(DOCKER_BASE_RELEASE_IMAGE)),)
+DOCKER_CMD_FLAGS    += --build-arg RELEASE_IMAGE=$(strip $(DOCKER_BASE_RELEASE_IMAGE))
+endif
 # use this variable for image labels added in internal build process
 LABEL               ?= org.airshipit.build=community
 COMMIT              ?= $(shell git rev-parse HEAD)
@@ -50,7 +58,7 @@ NO_PROXY            ?= localhost,127.0.0.1,.svc.cluster.local
 USE_PROXY           ?= false
 
 # docker build flags
-DOCKER_CMD_FLAGS    := --network=host
+DOCKER_CMD_FLAGS    += --network=host
 DOCKER_CMD_FLAGS    += --force-rm=$(DOCKER_FORCE_CLEAN)
 
 DOCKER_PROXY_FLAGS  := --build-arg http_proxy=$(PROXY)
@@ -80,7 +88,14 @@ export KUBECTL_URL  ?= https://storage.googleapis.com/kubernetes-release/release
 PLUGINS_DIR         := krm-functions
 PLUGINS             := $(subst $(PLUGINS_DIR)/,,$(wildcard $(PLUGINS_DIR)/*))
 PLUGINS_IMAGE_TGT   := $(foreach tgt,$(PLUGINS),docker-image-$(tgt))
-PLUGINS_BASE_IMAGE  ?= alpine:3.12.0
+# use this variables to override base images in internal build process
+ifneq ($(strip $(DOCKER_BASE_PLUGINS_BUILD_IMAGE)),)
+DOCKER_CMD_FLAGS    += --build-arg PLUGINS_BUILD_IMAGE=$(strip $(DOCKER_BASE_PLUGINS_BUILD_IMAGE))
+endif
+ifneq ($(strip $(DOCKER_BASE_PLUGINS_RELEASE_IMAGE)),)
+DOCKER_CMD_FLAGS    += --build-arg PLUGINS_RELEASE_IMAGE=$(strip $(DOCKER_BASE_PLUGINS_RELEASE_IMAGE))
+endif
+
 
 $(PLUGINS):
 	 @CGO_ENABLED=0 go build -o $(BINDIR)/$@ $(GO_FLAGS) ./$(PLUGINS_DIR)/$@/
@@ -168,7 +183,6 @@ $(PLUGINS_IMAGE_TGT):
 		--target $(DOCKER_TARGET_STAGE) \
 		--build-arg MAKE_TARGET=$(plugin_name) \
 		--build-arg BINARY=$(plugin_name) \
-		--build-arg RELEASE_IMAGE=$(PLUGINS_BASE_IMAGE) \
 		--tag $(DOCKER_REGISTRY)/$(DOCKER_IMAGE_PREFIX)/$(plugin_name):$(DOCKER_IMAGE_TAG)
 ifeq ($(PUBLISH), true)
 	@docker push $(DOCKER_REGISTRY)/$(DOCKER_IMAGE_PREFIX)/$(plugin_name):$(DOCKER_IMAGE_TAG)
diff --git a/krm-functions/toolbox/Dockerfile b/krm-functions/toolbox/Dockerfile
index d431b1400..52c68aac4 100644
--- a/krm-functions/toolbox/Dockerfile
+++ b/krm-functions/toolbox/Dockerfile
@@ -1,8 +1,9 @@
-ARG RELEASE_IMAGE=scratch
-FROM ${RELEASE_IMAGE} as kctl
+ARG GO_IMAGE=gcr.io/gcp-runtimes/go1-builder:1.15
+ARG PLUGINS_BUILD_IMAGE=alpine:3.12.0
+ARG PLUGINS_RELEASE_IMAGE=alpine:3.12.0
+FROM ${PLUGINS_BUILD_IMAGE} as ctls
 
 RUN apk update && apk add curl
-
 # Inject custom root certificate authorities if needed
 # Docker does not have a good conditional copy statement and requires that a source file exists
 # to complete the copy function without error.  Therefore the README.md file will be copied to
@@ -12,9 +13,11 @@ RUN update-ca-certificates
 
 RUN curl -L "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl" \
       -o /kubectl
-RUN chmod +x /kubectl
+RUN curl -L  "https://github.com/projectcalico/calicoctl/releases/download/v3.18.1/calicoctl" \
+      -o /calicoctl
+RUN chmod +x /kubectl /calicoctl
 
-FROM gcr.io/gcp-runtimes/go1-builder:1.15 as builder
+FROM ${GO_IMAGE} as builder
 ENV CGO_ENABLED=0
 WORKDIR /go/src/
 COPY krm-functions/toolbox/image/go.mod .
@@ -22,23 +25,7 @@ RUN /usr/local/go/bin/go mod download
 COPY krm-functions/toolbox/main.go .
 RUN /usr/local/go/bin/go build -v -o /usr/local/bin/config-function ./
 
-FROM ${RELEASE_IMAGE} as calicoctl
-
-RUN apk update && apk add curl
-
-# Inject custom root certificate authorities if needed
-# Docker does not have a good conditional copy statement and requires that a source file exists
-# to complete the copy function without error.  Therefore the README.md file will be copied to
-# the image every time even if there are no .crt files.
-COPY ./certs/* /usr/local/share/ca-certificates/
-RUN update-ca-certificates
-
-RUN curl -L  "https://github.com/projectcalico/calicoctl/releases/download/v3.18.1/calicoctl" \
-      -o /calicoctl
-RUN chmod +x /calicoctl
-
-FROM ${RELEASE_IMAGE} as release
-COPY --from=kctl /kubectl /usr/local/bin/kubectl
-COPY --from=calicoctl /calicoctl /usr/local/bin/calicoctl
+FROM ${PLUGINS_RELEASE_IMAGE} as release
+COPY --from=ctls /kubectl /calicoctl /usr/local/bin/
 COPY --from=builder /usr/local/bin/config-function /usr/local/bin/config-function
 CMD ["/usr/local/bin/config-function"]
diff --git a/roles/airshipctl-build-images/tasks/main.yaml b/roles/airshipctl-build-images/tasks/main.yaml
index 7e79308b5..5d1e5ab7f 100644
--- a/roles/airshipctl-build-images/tasks/main.yaml
+++ b/roles/airshipctl-build-images/tasks/main.yaml
@@ -18,6 +18,10 @@
       PROXY: "{{ proxy.http }}"
       NO_PROXY: "{{ proxy.noproxy }}"
       USE_PROXY: "{{ proxy.enabled | lower }}"
+      DOCKER_BASE_GO_IMAGE: "{{ docker.base_go_image | default(omit) }}"
+      DOCKER_BASE_RELEASE_IMAGE: "{{ docker.base_release_image | default(omit) }}"
+      DOCKER_BASE_PLUGINS_BUILD_IMAGE: "{{ docker.base_plugins_build_image | default(omit) }}"
+      DOCKER_BASE_PLUGINS_RELEASE_IMAGE: "{{ docker.base_plugins_release_image | default(omit) }}"
 
 - name: Verify Image Exists
   shell: docker image inspect "$(make print-docker-image-tag)"
diff --git a/roles/airshipctl-publish-images/tasks/main.yaml b/roles/airshipctl-publish-images/tasks/main.yaml
index 9fe9a7e12..88503242f 100644
--- a/roles/airshipctl-publish-images/tasks/main.yaml
+++ b/roles/airshipctl-publish-images/tasks/main.yaml
@@ -28,28 +28,22 @@
         password: "{{ airshipctl_image_repo_credentials.password }}"
         registry_url: "{{ image_repo }}"
 
-    - name: Push Image with Latest Tag
+    - name: Push Image with Tags
       make:
         chdir: "{{ zuul.project.src_dir }}"
         params:
-          DOCKER_IMAGE_TAG: latest
-          PUBLISH: "true"
-          PROXY: "{{ proxy.http }}"
-          NO_PROXY: "{{ proxy.noproxy }}"
-          USE_PROXY: "{{ proxy.enabled | lower }}"
-          DOCKER_REGISTRY: "{{ image_repo }}"
-          DOCKER_IMAGE_PREFIX: "{{ image_prefix | default('airshipit') }}"
-        target: images
-
-    - name: Push Image with Commit Tag
-      make:
-        chdir: "{{ zuul.project.src_dir }}"
-        params:
-          DOCKER_IMAGE_TAG: "{{ zuul.newrev }}"
+          DOCKER_IMAGE_TAG: "{{ item }}"
           PUBLISH: "true"
           PROXY: "{{ proxy.http }}"
           NO_PROXY: "{{ proxy.noproxy }}"
           USE_PROXY: "{{ proxy.enabled | lower }}"
           DOCKER_REGISTRY: "{{ image_repo }}"
           DOCKER_IMAGE_PREFIX: "{{ image_prefix | default('airshipit') }}"
+          DOCKER_BASE_GO_IMAGE: "{{ docker.base_go_image | default(omit) }}"
+          DOCKER_BASE_RELEASE_IMAGE: "{{ docker.base_release_image | default(omit) }}"
+          DOCKER_BASE_PLUGINS_BUILD_IMAGE: "{{ docker.base_plugins_build_image | default(omit) }}"
+          DOCKER_BASE_PLUGINS_RELEASE_IMAGE: "{{ docker.base_plugins_release_image | default(omit) }}"
         target: images
+      loop:
+        - "latest"
+        - "{{ zuul.newrev }}"
diff --git a/zuul.d/projects.yaml b/zuul.d/projects.yaml
index 0ee2443a2..1e9ac0823 100644
--- a/zuul.d/projects.yaml
+++ b/zuul.d/projects.yaml
@@ -19,6 +19,12 @@
         https: ""
         noproxy: ""
       image_repo: quay.io
+      docker:
+        base_go_image: ""
+        base_release_image: ""
+        base_plugins_build_image: ""
+        base_plugins_release_image: ""
+
     check:
       jobs:
         - openstack-tox-docs: &docs