Creating your own Homebrew tap and grabbing binaries from S3
Tags: aws, devops, forme
Published: 2021-07-29 20:24:16

Recently, I set up my own homebrew in order to easily distribute a `kubectl` plugin binary that I created. By creating my own homebrew, it allows me to easily download the binaries to any home dev environment without having to pull down the code from GitHub, compile it, and then add it somewhere in my $PATH in order to utilize it globally. 

I ran into a few hiccups along the way, so I figured it's best to document it for next time (or if someone stumbles into this post)

## Set up your own homebrew repo in GitHub

For my personal repo, I opted to name it `homebrew-homebrew`, as you can see here: [https://github.com/lucassha/homebrew-homebrew](https://github.com/lucassha/homebrew-homebrew).

The reason I chose this is because of the naming convention when tapping a new repository in brew. If, for instance, I named my repository `homebrew-lucassha` then I would have to run `brew tap lucassha/lucassha`. `brew` is specifically looking for repositories prepended with `homebrew-`. 

Now, I'll tap my instance: `brew tap lucassha/homebrew`. You can then see all tapped repositories with just `brew tap`. 

## Add the formula to download from S3

Once you have the repo set up, you'll need to add a formula to it. Here is my specific example:

```rb
class ShowSecrets < Formula
    desc "CLI to show decoded Kubernetes secrets"
    homepage "https://github.com/lucassha/show-secrets"
    url "https://lucassha-show-secrets-releases.s3.us-west-2.amazonaws.com/releases/v0.0.1"
    
    # to get the latest SHA:
    # find latest release: aws s3api list-objects --bucket lucassha-show-secrets-releases | jq '.Contents[].Key'
    # download release: aws s3 cp s3://lucassha-show-secrets-releases/releases/v0.0.1 . 
    # get sha: shasum -a 256 v0.0.1
    sha256 "36018cff6708dea3587c086e366ff80bed7a2750ddda9aa7e8c1af8311b17649"

    depends_on "kubernetes-cli"

    def install
        bin.install "show-secrets"
        # add kubectl binary to make it a kubectl plugin
        bin.install "kubectl-show-secrets"
    end

    def caveats; <<-EOS
        This tool may be used as a standalone CLI or a kubectl plugin
        # example
        show-secrets -n default
        kubectl show secrets -n default
    EOS
    end
end
```

The important bits to highlight here are the URL and SHA. Specifically, the URL is from S3 instead of a GitHub .tgz file. Similarly, the SHA is tarball that brew is using and not the binary. You must create a tarball.

## S3 Policies

Interestingly, I was surprised that a fully public bucket still needs a `GetBucket` policy in order to let an anonymous user download it. You can test this with a public bucket and just running `curl` against it. It will fail. Similarly, you'll get a `403` error when trying to install it via brew. Because of this, a bucket policy is needed. Here is the JSON I added for the public bucket:

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Allow Public Access to All Objects",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::lucassha-show-secrets-releases/*"
        }
    ]
}
```

## Install the binary

Now, you should be able to install the package! 
`brew install lucassha/homebrew/show-secrets`

This should create two binaries, which can be seen with this command: `which *show-secrets`

C'est tout!