Creating expired X.509 certificates

  • May 10, 2020
  • tuxotron
  • Expired Certificate

    Last week as I was preparing a the material for a workshop about TLS for developers, for one of the exercises, I needed to create an expired certificate.

    To do that I thought that when creating my certificate (self signed) all I had to do was to pass a negative number when specifying the numbers of days for the certificate validity.

    So there I went and run the following command:

    openssl req -x509 -newkey rsa:4096 -keyout server.key -out server.crt -days -5
    req: Non-positive number "-5" for -days
    req: Use -help for summary.
    

    As you can see, that didn’t work.

    After looking around for a bit, all the solutions I initially found, involved changing my system’s date and then generate the certificate. I didn’t like that option. So my next thought was to create the certificate in a Docker container. I would change the container’s date and then run my openssl command. Let’s try that:

    docker run -it --rm ubuntu:18.04
    root@c09ad5d2689d:/# date +%Y%m%d -s "20200101"
    date: cannot set date: Operation not permitted
    20200101
    root@c09ad5d2689d:/#
    

    As you can see that didn’t work either. Can you change the date from inside the container? You could, but to do that you need to run the container with higher privileges (–privileged). The reason for this is that the container shares the system’s clock, and therefore, changing the date inside the container would also change the host’s date. So back to square number 1.

    I went back to look for other options and finally I found this nice tool called faketime. According to its documentation this is just a simple layer on top of libfaketime. This last one is a library that capture some system calls (time and fstats) and allows you using the LD_PRELOAD functionality to set a specific date and time for a particular application.

    So going back to my quest, let’s create a certificate only valid for 1 day between the 1st and 2nd of January of 2020:

    faketime '2020-01-01' openssl req -x509 -newkey rsa:4096 -keyout server.key -out server.crt -days 1
    

    Let’s verify that our certificate has the validity period we meant to set:

    openssl x509 -in server.crt -text -noout
    
    ...
        Validity
            Not Before: Jan  1 00:00:05 2020 GMT
            Not After : Jan  2 00:00:05 2020 GMT
    ...
    

    That worked!

    faketime accepts different ways to set the date and time:

    faketime 'last Friday 5 pm' /bin/date
    faketime '2008-12-24 08:15:42' /bin/date
    faketime -f '+2,5y x10,0' /bin/bash -c 'date; while true; do echo $SECONDS ; sleep 1 ; done'
    ...
    ...
    

    You can either install faketime in your system or you can use a Docker container. If you take the container option you can do this manually or using doig:

    doig -u -i mytools -t faketime
    

    And then run your container:

    docker run -it --rm mytools
    

    From there you mess with faketime without having to worry messing up your system’s date.

    By the way, if you are looking for “certificates with issues”, https://badssl.com is a great resource to find all kind of certificates with different issues.

Docker image generator for infosec

  • April 12, 2020
  • tuxotron
  • Docker Image Creator

    This is a project I have entertained in my head for a while with my brother in arms Fran Ramírez, and finally I have found some time to work on it.

    The idea is pretty simple. Basically it is to create a Docker image with number of tools of your choice, without having to create or know how to create a Docker image itself.

    For instance, let’s say we want to run sqlmap, and we don’t have with us our lovely Kali distro, and we don’t want to install it in our system. A very convenience and clean way would be to run such tool from inside a Docker container. We spin up the container, run the tool, exit and all done. Our stays “clean”.

    To do that, we would have to create a Dockerfile, with the instructions to install sqlmap, and then create the Docker image from it. Or maybe find an already existing Docker image and use it.

    Docker Image Generator is a project that helps you to create Docker images without having to create a Dockerfile and build it yourself, with the tools you choose, as long as they are available in the project.

    Right now, the focus of this project is infosec, therefore all the tools available are security related, but it could perfectly be extended with any other tool that can run inside a Docker container.

    I have created the binaries for Linux, MacOS and Windows for your convenience, but if you prefer building the binary yourself, you will need a go version that supports modules, cloning the repository and run:

    go build
    

    Or use make

    make build
    

    Either if you have downloaded the .tgz linked above and extracted its content, or you cloned and compiled the code yourself, you should have at least: a binary called doig, a directory called tools and a file called Dockerfile.template.

    If you look inside the tools directory, you can see all the tools available. Those files are simple .ini text files with some properties that defines: the name, category and the command that needs to run as part of the RUN Dockerfile instruction.

    To see some examples of use, please check out the repository of the project.

    The project is in an early phase and I’m working on improving the code (refactoring, testing, etc), adding new functionality and more tools. By the way, pull requests are welcome!

    I would like to thank some friends: Oscar for his active collaboration, as well as: Fran, Alberto end Enrique, for their ideas and support.

Extending kubectl

  • September 7, 2019
  • tuxotron
  • Kubectl

    *Kubectl Plugin*

    As you probably already know, kubectl is the official tool to interact with Kubernetes from the command line. This tool, besides all the functionality that it already provides, allows us to extend its functionality through plugins.

    A kubectl plugin is nothing but a file with the following three requirements:

    • It has to be an executable (binary or script)
    • It must be in your system’s PATH
    • Its name must start with kubectl- (including the dash!)

    The plugin system in kubectl was introduced as alpha in version 1.8.0 and it was rewritten in version 1.12.0, which is the minimum version recommended if you are going to play with this feature.

    Let’s write our first plugin. It will be a bash script named kubectl-hello. This is its content:

    #!/bin/bash
    
    echo "Hello, World!"
    

    Prefixing the file name with kubectl- is one of the requirements. Another requirement is to make it an executable:

    chmod +x kubectl-hello
    

    The last requirement is to make sure the file is somewhere in the PATH. You can either copy the file to a directory that is already in the PATH, or make the directory you created the file in, part of the PATH. In our case, we’ll take the second approach:

    export PATH=$PATH:~/tmp/kplugin
    

    This command only takes effect in the session where you run it. Once that session is closed (or opening a different terminal), your directory will no longer be part of your PATH. To make it persistent you will need to add that command to your ~/.bashrc, ~/.zshrc or something similar.

    Now we can run our plugin:

    kubectl hello
    Hello, World!
    

    Let’s create another plugin, a little bit more useful this time. In this case will also be a bash script. This plugin will generate a configuration file with the given account’s credentials (in this case a service account). This is pretty handy when you need to interact with a Kubernetes cluster from, let’s say your CI/CD server. In order to get your server access to the cluster, you will need to provide some type of credential. So you can use this plugin to create the configuration file based on a service account with the necessary credentials and cluster information.

    Our file will have the following content:

    #!/bin/bash
    
    set -e
    
    usage="
    USAGE: 
      kubectl kubeconf-generator -a SERVICE_ACCOUNT -n NAMESPACE
    "
    
    while getopts a:n: option
    do
    case "${option}"
    in
    a) SA=${OPTARG};;
    n) NAMESPACE=${OPTARG};;
    esac
    done
    
    [[ -z "$SA" ]] && { echo "Service account is required" ; echo "$usage" ; exit 1; }
    [[ -z "$NAMESPACE" ]] && { echo "Namespace is required" ; echo "$usage" ; exit 1; }
    
    # Get secret name
    SECRET_NAME=($(kubectl get sa $SA -n $NAMESPACE -o jsonpath='{.secrets[0].name}'))
      
    # Get secret value
    SECRET=$(kubectl get secret $SECRET_NAME -n $NAMESPACE -o jsonpath='{.data.token}' | base64 -D)
    
    # Get cluster server name
    SERVER=$(kubectl config view --minify -o json | jq -r '.clusters[].cluster.server')
    # Get cluster name
    CLUSTER_NAME=$(kubectl config view --minify -o json | jq -r '.clusters[].name')
    
    # Get cluster certs
    CERTS=$(kubectl config view --raw --minify -o json | jq -r '.clusters[].cluster."certificate-authority-data"')
    
    cat << EOM
    apiVersion: v1
    kind: Config
    users:
    - name: $SA
      user:
        token: $SECRET
    clusters:
    - cluster:
        certificate-authority-data: $CERTS
        server: $SERVER
      name: $CLUSTER_NAME
    contexts:
    - context:
        cluster: $CLUSTER_NAME
        user: $SAS
      name: svcs-acct-context
    current-context: svcs-acct-context
    EOM
    

    As you can see, this plugin, besides kubectl also uses jp. So to make it work, you need to have such tool installed as well.

    The plugin expects two parameters: the service account and the namespace for such account.

    Let’s dump the content listed above into a file named kubectl-kubeconf_generator. Pay attention to the underscore character. We’ll come back to this later.

    Let’s run our plugin without any parameters:

    kubectl kubeconf_generator
    Service account is required
    
    USAGE:
      kubectl-kubeconf_generator -a SERVICE_ACCOUNT -n NAMESPACE
    

    Now let’s call it with the service account (default) and namespace (default). Now this time the plugin will try to fetch some information from the cluster defined in your current context. In this case I’m using minikube (if you are too, make sure it is up and running):

    kubectl kubeconf_generator -a default -n default
    apiVersion: v1
    kind: Config
    users:
    - name: default
      user:
        token: REDACTADO
    clusters:
    - cluster:
        certificate-authority-data: null
        server: https://192.168.99.110:8443
      name: minikube
    contexts:
    - context:
        cluster: minikube
        user:
      name: svcs-acct-context
    current-context: svcs-acct-context
    

    The output is a configuration file we could use to provide access to our minikube using the default service account from the default namespace (with whatever permissions granted to that account).

    Let’s go back to the name of the file. Remember, in our case we named our file as kubectl-kubeconf_generator. When kubectl sees an underscore character in the plugin name, it will allow us to call the plugin either with the underscore or a dash:

    kubectl kubeconf_generator -a default -n default
    ...
    

    o kubectl kubeconf-generator -a default -n default …

    Now, if you rename our file to kubectl-kubeconf-generator (replace the underscore with a dash), kubectl recognizes as a command and subcommand. So to call it this time, we will have to have a blank space between kubeconf and generator:

    kubectl kubeconf generator -a default -n default
    ...
    

    Following this pattern we can create subcommands for our plugin command. For instance, imagine we want to be able to generate two different output formats: yaml and json. We could create two files:

    kubectl-kubeconf-generator-yaml
    kubectl-kubeconf-generator-json
    

    This way to invoke them:

    kubectl kubeconf generator json ...
    ...
    kubectl kubeconf generator yaml ...
    ...
    

    This example is not the best way to customize the output. For that you may want to use a parameter, in this case probably -o to align with kubectl “standards”.

    To wrap up, it is worth to mention that you can’t override an existing kubectl command. For instance, kubectl provides the version command, so if you create a new plugin and named kubectl-version, when you call kubectl version, the internal version command will be called and not your plugin. Also there are some rules about name conflicts, when you have two plugins with the same name in different directories, etc, but I’m not going to touch on those rules in this entry. You can always consult the official documentation linked at the beginning of this post.

    Last but not least, I just want to mention that kubectl has a plugin command with the list option which will show us the kubectl plugins in our system:

    kubectl plugin list
    The following compatible plugins are available:
    
    /Users/tuxotron/tmp/kplugin/kubectl-hello
    /Users/tuxotron/tmp/kplugin/kubectl-kubeconf-generator
    

    In a future entry I will talk about a cleaner way to handle and install plugins.