diff --git a/Makefile b/Makefile index 34df2b7ab..9f28c47fe 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,15 @@ default: ci -ci: lint test fmt-check imports-check - -export GOFLAGS=-mod=vendor +ci: lint test fmt-check imports-check build-cli-cross-platform GOLANGCILINTVERSION?=1.23.8 COVERAGEOUT?=coverage.out CLINAME?=lacework-cli +GO_LDFLAGS="-X github.com/lacework/go-sdk/cli/cmd.Version=$(shell cat cli/VERSION) \ + -X github.com/lacework/go-sdk/cli/cmd.GitSHA=$(shell git rev-parse HEAD) \ + -X github.com/lacework/go-sdk/cli/cmd.BuildTime=$(shell date +%Y%m%d%H%M%S)" +GOFLAGS=-mod=vendor +export GOFLAGS GO_LDFLAGS prepare: install-tools go-vendor @@ -37,11 +40,24 @@ fmt-check: imports-check: @test -z $(shell goimports -l $(shell go list -f {{.Dir}} ./...)) -build-cli: - go build -o bin/$(CLINAME) cli/main.go - @echo - @echo To execute the generated binary run: - @echo " ./bin/$(CLINAME)" +build-cli-cross-platform: + gox -output="bin/$(CLINAME)-{{.OS}}-{{.Arch}}" \ + -os="darwin linux windows" \ + -arch="amd64 386" \ + -ldflags=$(GO_LDFLAGS) \ + github.com/lacework/go-sdk/cli + +install-cli: build-cli-cross-platform +ifeq (x86_64, $(shell uname -m)) + ln -sf bin/$(CLINAME)-$(shell uname -s | tr '[:upper:]' '[:lower:]')-amd64 bin/$(CLINAME) +else + ln -sf bin/$(CLINAME)-$(shell uname -s | tr '[:upper:]' '[:lower:]')-386 bin/$(CLINAME) +endif + @echo "\nUpdate your PATH environment variable to execute the compiled lacework-cli:" + @echo "\n $$ export PATH=\"$(PWD)/bin:$$PATH\"\n" + +release-cli: lint fmt-check imports-check test + scripts/lacework_cli_release.sh install-tools: ifeq (, $(shell which golangci-lint)) @@ -50,3 +66,6 @@ endif ifeq (, $(shell which goimports)) go get golang.org/x/tools/cmd/goimports endif +ifeq (, $(shell which gox)) + go get github.com/mitchellh/gox +endif diff --git a/README.md b/README.md index 4d352415c..fc03d4bb5 100644 --- a/README.md +++ b/README.md @@ -33,16 +33,21 @@ Look at the [api/](api/) folder for more documentation. ## Lacework CLI ([`cli`](cli/)) -_(work-in-progress)_ The Lacework Command Line Interface. +The Lacework Command Line Interface. ### Basic Usage -Today, you have to first build the CLI by running `make build-cli`, then you will be -able to execute it directly: +Build and install the CLI by running `make install-cli`, the automation will +ask you to update your `PATH` environment variable to execute the compiled +`lacework-cli` binary. ``` -$ make build-cli -$ ./bin/lacework-cli +$ make install-cli + +# Make sure to update your PATH with the command provided from the above command + +$ lacework-cli help ``` +Look at the [cli/](cli/) folder for more documentation. ## License and Copyright Copyright 2020, Lacework Inc. diff --git a/cli/README.md b/cli/README.md new file mode 100644 index 000000000..f5cd1091e --- /dev/null +++ b/cli/README.md @@ -0,0 +1,80 @@ + + +# `lacework-cli` + +The Lacework Command Line Interface is a tool that helps you manage your +Lacework cloud security platform. You can use it to manage compliance +reports, external integrations, vulnerability scans, and other operations. + +## Install + +### Bash: +``` +$ curl https://raw.githubusercontent.com/lacework/go-sdk/master/cli/install.sh | sudo bash +``` + +### Powershell: +``` +C:\> Set-ExecutionPolicy Bypass -Scope Process -Force +C:\> iex ((New-Object System.Net.WebClient).DownloadString('https://raw.githubusercontent.com/lacework/go-sdk/master/cli/install.ps1')) +``` + +## Configuration File + +The `lacework-cli` looks for a file named `.lacework.toml` inside your home +directory (`$HOME/.lacework.toml`) to access the following parameters: +* `account`: Account subdomain of URL (i.e. `.lacework.net`) +* `api_key`: API Access Key ID +* `api_secret`: API Access Secret Key + + +An example of a Lacework configuration file: +```toml +account = "example" +api_key = "EXAMPLE_1234567890ABC" +api_secret = "_super_secret_key" +``` + +You can provide a different configuration file with the option `--config`. + +## Basic Usage +Once you have created your configuration file `$HOME/.lacework.toml`, +you are ready to use the Lacework cli, a few basic commands are: + +1) List all integration in your account: +```bash +$ lacework-cli integration list +``` +1) Use the `api` command to access Lacework's ResfulAPI, for example, +to get details about and specific event: +```bash +$ lacework-cli api get '/external/events/GetEventDetails?EVENT_ID=16700' +``` + +## Development +To build and install the CLI from source, use the `make install-cli` directive, +this command will ask you to update your `PATH` environment variable to point +to the compiled `lacework-cli` binary. +``` +$ make install-cli + +# Make sure to update your PATH with the command provided from the above command + +$ lacework-cli help +``` + +## License and Copyright +Copyright 2020, Lacework Inc. +``` +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +``` diff --git a/cli/install.ps1 b/cli/install.ps1 new file mode 100644 index 000000000..73c977c85 --- /dev/null +++ b/cli/install.ps1 @@ -0,0 +1,13 @@ +<# +.SYNOPSIS +Installs the 'lacework-cli' tool. + +.Parameter Version +Specifies a version (ex: 0.1.0) +#> + +$ErrorActionPreference="stop" + +Set-Variable GithubReleasesRootUrl -Option ReadOnly -value "https://github.com/lacework/go-sdk/releases" + +Write-Host "Comming soon! (Installatiohn of the 'lacework-cli' tool)" diff --git a/cli/install.sh b/cli/install.sh new file mode 100755 index 000000000..8ef0baeda --- /dev/null +++ b/cli/install.sh @@ -0,0 +1,230 @@ +#!/bin/bash +# +set -eou pipefail + +# If the variable $LW_DEBUG is set, print all shell commands executed +if [ -n "${LW_DEBUG:-}" ]; then set -x; fi + +readonly github_releases="https://github.com/lacework/go-sdk/releases" + +usage() { + local _cmd + _cmd="$(basename "${0}")" + cat <&2 + usage >&2 + exit_with "Invalid option" 1 + ;; + esac + done + + log "Installing the 'lacewor-cli' tool" + create_workdir + check_platform + download_archive "$version" "$target" + verify_archive + extract_archive + install_cli + print_cli_version + log "The 'lacework-cli' tool has been successfully installed." +} + +create_workdir() { + if [ -d /var/tmp ]; then + local _tmp=/var/tmp + else + local _tmp=/tmp + fi + + workdir="$(mktemp -d -p "$_tmp" 2> /dev/null || mktemp -d "${_tmp}/lacework.XXXX")" + # add a trap to clean up work directory + trap 'code=$?; rm -rf $workdir; exit $code' INT TERM EXIT + cd "${workdir}" +} + +check_platform() { + local _ostype + _ostype="$(uname -s)" + + case "${_ostype}" in + Darwin|Linux) + sys="$(uname -s | tr '[:upper:]' '[:lower:]')" + arch="$(uname -m | tr '[:upper:]' '[:lower:]')" + ;; + *) + exit_with "unable to determine OS platform type: ${_ostype}" 2 + ;; + esac + + case "${sys}" in + darwin) + ext=zip + shasum_cmd="shasum -a 256" + ;; + linux) + ext=tar.gz + shasum_cmd="sha256sum" + ;; + *) + exit_with "unable to determine system type, perhaps is not supported: ${sys}" 3 + ;; + esac + + # The following architectures match our cross-platform build process + # https://golang.org/doc/install/source#environment + case "${arch}" in + x86_64) + arch=amd64 + ;; + i686) + arch=386 + ;; + *) + exit_with "architecture not supported: ${arch}" 3 + ;; + esac + + if [ -z "${target:-}" ]; then + target="${sys}-${arch}" + fi +} + +download_archive() { + local _version="${1:-latest}" + local -r _target="${2:?}" + local url + + if [ "$_version" == "latest" ]; then + url="${github_releases}/latest/download/lacework-cli-${_target}.${ext}" + else + url="${github_releases}/download/${_version}/lacework-cli-${_target}.${ext}" + fi + + download_file "${url}" "${workdir}/lacework-cli-${_version}.${ext}" + download_file "${url}.sha256sum" "${workdir}/lacework-cli-${_version}.${ext}.sha256sum" + + archive="lacework-cli-${_target}.${ext}" + sha_file="lacework-cli-${_target}.${ext}.sha256sum" + + mv -v "${workdir}/lacework-cli-${_version}.${ext}" "${archive}" + mv -v "${workdir}/lacework-cli-${_version}.${ext}.sha256sum" "${sha_file}" +} + +verify_archive() { + log "Verifying the shasum digest matches the downloaded archive" + ${shasum_cmd} -c "${sha_file}" +} + +extract_archive() { + log "Extracting ${archive}" + case "${ext}" in + tar.gz) + archive_dir="${archive%.tar.gz}" + mkdir "${archive_dir}" + zcat "${archive}" | tar --extract --directory "${archive_dir}" --strip-components=1 + + ;; + zip) + archive_dir="${archive%.zip}" + unzip -j "${archive}" -d "${archive_dir}" + ;; + *) + exit_with "[extract] Unknown file extension: ${ext}" 4 + ;; + esac +} + +install_cli() { + log "Installing lacework-cli into /usr/local/bin" + mkdir -pv /usr/local/bin + binary="lacework-cli-${target}" + install -v "${archive_dir}/lacework-cli-"* /usr/local/bin/lacework-cli +} + +print_cli_version() { + info "Verifying installed lacework-cli version" + lacework-cli version +} + +download_file() { + local _url="${1}" + local _dst="${2}" + local _code + local _wget_extra_args="" + local _curl_extra_args="" + + # try to download with wget + if command -v wget > /dev/null; then + log "Downloading via wget: ${_url}" + + wget -q -O "${_dst}" "${_url}" + _code="$?" + + if [ $_code -eq 0 ]; then + return 0 + else + warn "wget failed to download file, trying to download with curl" + fi + fi + + # try to download with curl + if command -v curl > /dev/null; then + log "Downloading via curl: ${_url}" + + curl -sSfL "${_url}" -o "${_dst}" + _code="$?" + + if [ $_code -eq 0 ]; then + return 0 + else + warn "curl failed to download file" + fi + fi + + # wget and curl have failed, inform the user + exit_with "Required: SSL-enabled 'curl' or 'wget' on PATH with" 6 +} + +log() { + echo "--> install: $1" +} + +warn() { + echo "xxx install: $1" >&2 +} + +exit_with() { + warn "$1" + exit "${2:-10}" +} + +main "$@" || exit 99 diff --git a/scripts/lacework_cli_release.sh b/scripts/lacework_cli_release.sh new file mode 100755 index 000000000..1485d16fb --- /dev/null +++ b/scripts/lacework_cli_release.sh @@ -0,0 +1,107 @@ +#!/bin/bash +# +# Name:: lacework_cli_release.sh +# Description:: Use this script to prepare a new release on Github, +# the automation will build cross-platform binaries, +# compress all generated targets, generate shasum +# hashes, and create a GH tag like v0.1.0 (using the +# VERSION file inside the cli/ directory) +# Author:: Salim Afiune Maya () +# +set -eou pipefail + +CLINAME=lacework-cli +VERSION=$(cat cli/VERSION) +TARGETS=( + ${CLINAME}-darwin-386 + ${CLINAME}-darwin-amd64 + ${CLINAME}-windows-386.exe + ${CLINAME}-windows-amd64.exe + ${CLINAME}-linux-386 + ${CLINAME}-linux-amd64 +) + +main() { + log "Preparing release v$VERSION" + prerequisites + build_cli_cross_platform + compress_targets + generate_shasums + create_git_tag +} + +create_git_tag() { + local _tag="v$VERSION" + log "Creating github tag: $_tag" + git tag "$_tag" + git push origin "$_tag" + log "Go to https://github.com/lacework/go-sdk/releases and upload all files from 'bin/'" +} + +prerequisites() { + if ! command -v "gox" > /dev/null 2>&1; then + warn "Required command 'gox' not found on PATH" + warn "Try running 'make prepare'" + exit 127 + fi + + local _branch=$(git rev-parse --abbrev-ref HEAD) + if [ "$_branch" != "master" ]; then + warn "Releases must be generated from the 'master' branch. (current $_branch)" + warn "Switch to the master branch and try again." + exit 127 + fi +} + +clean_cache() { + rm -rf bin/* +} + +build_cli_cross_platform() { + clean_cache + make build-cli-cross-platform +} + +generate_shasums() { + ( cd bin/ + local _compressed + log "Generating sha256sum Hashes" + for target in ${TARGETS[*]}; do + + if [[ "$target" =~ /linux/ ]]; then + _compressed="$target.tar.gz" + else + _compressed="$target.zip" + fi + + log "bin/$_compressed.sha256sum" + shasum -a 256 $_compressed > $_compressed.sha256sum + + done + ) +} + +# compress_targets will compress all targets and remove the raw +# binaries (already compressed), this is a release so we don't +# need the raw binaries anymore. +compress_targets() { + log "Compressing target binaries" + for target in ${TARGETS[*]}; do + if [[ "$target" =~ /linux/ ]]; then + tar -czvf "bin/${target}.tar.gz" "bin/${target}" + else + zip "bin/${target}.zip" "bin/${target}" + fi + rm -f "bin/${target}" + done +} + +log() { + echo "--> ${CLINAME}: $1" +} + +warn() { + echo "xxx ${CLINAME}: $1" >&2 +} + +main || exit 99