Skip to content

Commit

Permalink
feat: AWS / GCP / Azure CLI connections
Browse files Browse the repository at this point in the history
* feat: download certain CLI tools in Docker image

[skip ci]

* chore: format Dockerfile

[skip ci]

* chore: update exec fixture to test if jq gets installed with arkade

* chore: make resources

* feat: support connections in AWS

* fix: Docker file

* feat: Gcloud exec with connection support

* feat: azure cli connection

* chore: gen resources and manifests

* feat: added aws to e2e test

* fix: add region to aws exec fixture

* fix: aws connection config saver

* debug: send generated credentials

* chore: disable other workflows for now and try a different s3 command

* chore: don't save region in credentials file

* fix: make use of session tokens

* chore: do not create aws credential file (just testing)

* make aws exec test run on a cron schedule

* chore: make crd and schema

* refactor: setup connection based on what's provided not based on the
command

* refactor: minimize docker image

* fix: save the credentials in the current directory

* chore: generate manifests.yaml
  • Loading branch information
adityathebe authored Aug 16, 2023
1 parent c5ae936 commit cc1c863
Show file tree
Hide file tree
Showing 23 changed files with 1,484 additions and 69 deletions.
53 changes: 53 additions & 0 deletions .github/workflows/aws-exec.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
name: AWS-exec-test

on:
schedule:
- cron: '0 0 * * *'

permissions:
contents: read
id-token: write

jobs:
test:
strategy:
fail-fast: false
matrix:
suite:
- aws/minimal
runs-on: ubuntu-latest
steps:
- name: Install Go
uses: actions/setup-go@bfdd3570ce990073878bf10f6b2d79082de49492 # v2.2.0
with:
go-version: 1.20.x
- name: Checkout code
uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
- uses: actions/cache@8492260343ad570701412c2f464a5877dc76bace # v2
with:
path: |
~/go/pkg/mod
~/.cache/go-build
.bin
key: cache-${{ hashFiles('**/go.sum') }}-${{ hashFiles('.bin/*') }}
restore-keys: |
cache-
- name: Build
run: make bin
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v2
with:
role-to-assume: arn:aws:iam::765618022540:role/canary-checker-github-iam-Role-N9JG51I5V3JJ
aws-region: us-east-1
role-duration-seconds: 1800 # 30 minutes
- name: Test
env:
KUBERNETES_VERSION: v1.20.7
GH_TOKEN: ${{ secrets.CHECKRUNS_TOKEN }}
run: ./test/e2e.sh fixtures/${{matrix.suite}}
- name: Publish Unit Test Results
uses: EnricoMi/publish-unit-test-result-action@b9f6c61d965bcaa18acc02d6daf706373a448f02 # v1.40
if: always() && github.event.repository.fork == 'false'
with:
files: test/test-results.xml
check_name: E2E - ${{matrix.suite}}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.bin/
.creds/
.release/
bin/
.idea/
Expand Down
50 changes: 44 additions & 6 deletions api/v1/checks.go
Original file line number Diff line number Diff line change
Expand Up @@ -822,6 +822,7 @@ type AWSConnection struct {
ConnectionName string `yaml:"connection,omitempty" json:"connection,omitempty"`
AccessKey types.EnvVar `yaml:"accessKey" json:"accessKey,omitempty"`
SecretKey types.EnvVar `yaml:"secretKey" json:"secretKey,omitempty"`
SessionToken types.EnvVar `yaml:"sessionToken,omitempty" json:"sessionToken,omitempty"`
Region string `yaml:"region,omitempty" json:"region,omitempty"`
Endpoint string `yaml:"endpoint,omitempty" json:"endpoint,omitempty"`
// Skip TLS verify when connecting to aws
Expand Down Expand Up @@ -856,17 +857,23 @@ func (t *AWSConnection) Populate(ctx checkContext, k8s kubernetes.Interface, nam
}

if accessKey, err := duty.GetEnvValueFromCache(k8s, t.AccessKey, namespace); err != nil {
return fmt.Errorf("could not parse EC2 access key: %v", err)
return fmt.Errorf("could not parse AWS access key id: %v", err)
} else {
t.AccessKey.ValueStatic = accessKey
}

if secretKey, err := duty.GetEnvValueFromCache(k8s, t.SecretKey, namespace); err != nil {
return fmt.Errorf(fmt.Sprintf("Could not parse EC2 secret key: %v", err))
return fmt.Errorf(fmt.Sprintf("Could not parse AWS secret access key: %v", err))
} else {
t.SecretKey.ValueStatic = secretKey
}

if sessionToken, err := duty.GetEnvValueFromCache(k8s, t.SessionToken, namespace); err != nil {
return fmt.Errorf(fmt.Sprintf("Could not parse AWS session token: %v", err))
} else {
t.SessionToken.ValueStatic = sessionToken
}

return nil
}

Expand All @@ -893,13 +900,37 @@ func (g *GCPConnection) HydrateConnection(ctx checkContext) error {
}

if connection != nil {
g.Credentials.ValueStatic = connection.Password
g.Credentials = &types.EnvVar{ValueStatic: connection.Certificate}
g.Endpoint = connection.URL
}

return nil
}

type AzureConnection struct {
ConnectionName string `yaml:"connection,omitempty" json:"connection,omitempty"`
ClientID *types.EnvVar `yaml:"clientID,omitempty" json:"clientID,omitempty"`
ClientSecret *types.EnvVar `yaml:"clientSecret,omitempty" json:"clientSecret,omitempty"`
TenantID string `yaml:"tenantID,omitempty" json:"tenantID,omitempty"`
}

// HydrateConnection attempts to find the connection by name
// and populate the endpoint and credentials.
func (g *AzureConnection) HydrateConnection(ctx checkContext) error {
connection, err := ctx.HydrateConnectionByURL(g.ConnectionName)
if err != nil {
return err
}

if connection != nil {
g.ClientID = &types.EnvVar{ValueStatic: connection.Username}
g.ClientSecret = &types.EnvVar{ValueStatic: connection.Password}
g.TenantID = connection.Properties["tenantID"]
}

return nil
}

type FolderCheck struct {
Description `yaml:",inline" json:",inline"`
Templatable `yaml:",inline" json:",inline"`
Expand All @@ -921,25 +952,32 @@ func (c FolderCheck) GetEndpoint() string {
return c.Path
}

type ExecConnections struct {
AWS *AWSConnection `yaml:"aws,omitempty" json:"aws,omitempty"`
GCP *GCPConnection `yaml:"gcp,omitempty" json:"gcp,omitempty"`
Azure *AzureConnection `yaml:"azure,omitempty" json:"azure,omitempty"`
}

type ExecCheck struct {
Description `yaml:",inline" json:",inline"`
Templatable `yaml:",inline" json:",inline"`
// Script can be a inline script or a path to a script that needs to be executed
// On windows executed via powershell and in darwin and linux executed using bash
Script *string `yaml:"script" json:"script"`
Script string `yaml:"script" json:"script"`
Connections ExecConnections `yaml:"connections,omitempty" json:"connections,omitempty"`
}

func (c ExecCheck) GetType() string {
return "exec"
}

func (c ExecCheck) GetEndpoint() string {
return *c.Script
return c.Script
}

func (c ExecCheck) GetTestFunction() Template {
if c.Test.Expression == "" {
c.Test.Expression = "results.ExitCode == 0"
c.Test.Expression = "results.exitCode == 0"
}
return c.Test
}
Expand Down
62 changes: 57 additions & 5 deletions api/v1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

101 changes: 60 additions & 41 deletions build/full/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ WORKDIR /app
ARG NAME
ARG VERSION
ENV IMAGE_TYPE=full

COPY go.mod /app/go.mod
COPY go.sum /app/go.sum
RUN go mod download

COPY ./ ./
RUN go version
RUN make build

FROM eclipse-temurin:11.0.18_10-jdk-focal@sha256:509043cc38d37a5bd44720b471c38bef40fb34de67c03baaa67a5a9d8cda52a0
Expand All @@ -20,22 +21,22 @@ RUN apt-get update && \
apt-get clean

RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - && \
echo "deb http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list && \
apt-get update && apt-get install -y \
google-chrome-stable \
fontconfig \
fonts-ipafont-gothic \
fonts-wqy-zenhei \
fonts-thai-tlwg \
fonts-kacst \
fonts-symbola \
fonts-noto \
fonts-freefont-ttf \
--no-install-recommends

RUN apt-get update && apt-get upgrade -y && \
rm -Rf /var/lib/apt/lists/* && \
apt-get clean
echo "deb http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list && \
apt-get update && apt-get install -y \
google-chrome-stable \
fontconfig \
fonts-ipafont-gothic \
fonts-wqy-zenhei \
fonts-thai-tlwg \
fonts-kacst \
fonts-symbola \
fonts-noto \
fonts-freefont-ttf \
--no-install-recommends

RUN apt-get update && apt-get upgrade -y && \
rm -Rf /var/lib/apt/lists/* && \
apt-get clean

ENV RESTIC_VERSION=0.15.2
RUN curl -L https://github.com/restic/restic/releases/download/v${RESTIC_VERSION}/restic_${RESTIC_VERSION}_linux_amd64.bz2 -o restic.bz2 && \
Expand All @@ -51,42 +52,60 @@ RUN curl -L https://dlcdn.apache.org//jmeter/binaries/apache-jmeter-${JMETER_VER

ENV PATH /opt/apache-jmeter-${JMETER_VERSION}/bin/:$PATH


RUN curl -L https://github.com/flanksource/askgit/releases/download/v0.4.8-flanksource/askgit-linux-amd64.tar.gz -o askgit.tar.gz && \
tar xf askgit.tar.gz && \
mv askgit /usr/local/bin/askgit && \
rm askgit.tar.gz && \
wget http://mirrors.kernel.org/ubuntu/pool/main/o/openssl/openssl_1.1.1f-1ubuntu2.19_amd64.deb && \
dpkg -i openssl_1.1.1f-1ubuntu2.19_amd64.deb && \
rm openssl_1.1.1f-1ubuntu2.19_amd64.deb

tar xf askgit.tar.gz && \
mv askgit /usr/local/bin/askgit && \
rm askgit.tar.gz && \
wget http://mirrors.kernel.org/ubuntu/pool/main/o/openssl/openssl_1.1.1f-1ubuntu2.19_amd64.deb && \
dpkg -i openssl_1.1.1f-1ubuntu2.19_amd64.deb && \
rm openssl_1.1.1f-1ubuntu2.19_amd64.deb

# The best developer experience for load testing
ENV K6_VERSION=v0.44.0
RUN curl -L https://github.com/grafana/k6/releases/download/${K6_VERSION}/k6-${K6_VERSION}-linux-amd64.tar.gz -o k6.tar.gz && \
tar xvf k6.tar.gz && \
mv k6-${K6_VERSION}-linux-amd64/k6 /usr/local/bin/k6 && \
rm k6.tar.gz
tar xvf k6.tar.gz && \
mv k6-${K6_VERSION}-linux-amd64/k6 /usr/local/bin/k6 && \
rm k6.tar.gz

# Benthos is a high performance and resilient stream processor
RUN curl -Lsf https://sh.benthos.dev | bash -s -- 4.15.0

# Commandline tool for running SQL queries against JSON, CSV, Excel, Parquet, and more
RUN curl -L https://github.com/multiprocessio/dsq/releases/download/v0.23.0/dsq-linux-x64-v0.23.0.zip -o dsq.zip && \
unzip dsq.zip && \
mv dsq /usr/local/bin/dsq && \
rm dsq.zip

RUN curl -L https://github.com/stern/stern/releases/download/v1.25.0/stern_1.25.0_linux_amd64.tar.gz -o stern.tar.gz && \
tar xvf stern.tar.gz && \
mv stern /usr/local/bin/stern && \
rm stern.tar.gz
unzip dsq.zip && \
mv dsq /usr/local/bin/dsq && \
rm dsq.zip

# install CA certificates
COPY --from=builder /app/.bin/canary-checker /app

RUN mkdir /opt/database
RUN groupadd --gid 1000 canary
RUN useradd canary --uid 1000 -g canary -m -d /var/lib/canary
RUN chown -R 1000:1000 /opt/database
RUN chown -R 1000:1000 /app
# Install alexellis/arkade as root
RUN curl -sLS https://get.arkade.dev | sh

# Install Azure CLI (need to install as root)
RUN curl -sL https://aka.ms/InstallAzureCLIDeb | bash

RUN mkdir /opt/database && groupadd --gid 1000 canary && \
useradd canary --uid 1000 -g canary -m -d /var/lib/canary && \
chown -R 1000:1000 /opt/database && chown -R 1000:1000 /app

USER canary:canary

# Install CLIs with arkade as canary user
RUN arkade get kubectl stern jq yq
ENV PATH="${PATH}:/var/lib/canary/.arkade/bin/"
ENV PATH="${PATH}:/var/lib/canary/bin/"

# Install AWS CLI
RUN curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" && \
unzip awscliv2.zip && ./aws/install -i ${HOME}/aws -b ${HOME}/bin/ && \
rm awscliv2.zip

# Install GCP CLI
RUN curl -sL -O https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-cli-441.0.0-linux-x86_64.tar.gz && \
tar -xf google-cloud-cli-441.0.0-linux-x86_64.tar.gz && \
ln -sf /app/google-cloud-sdk/bin/gcloud ${HOME}/bin/gcloud && \
rm google-cloud-cli-441.0.0-linux-x86_64.tar.gz

RUN /app/canary-checker go-offline
ENTRYPOINT ["/app/canary-checker"]
Loading

0 comments on commit cc1c863

Please sign in to comment.