Month: November 2021

Signed SSH Certificates using Hashicorp Vault in Practice

Signed SSH Certificates using Hashicorp Vault in Practice

In previous setup, root token is used all the time, which should not be the case in real situation.

Steps

Preparation of Vault and SSH Server

The steps can follow Signed SSH Certificates using Hashicorp Vault

Using root token

export VAULT_TOKEN=<root_token>
export VAULT_ADDR='http://host:8200'

Create Policy

$ vault policy write my-policy - << EOF
path "ssh-client-signer/sign/my-role" {
  capabilities = ["create", "update", "read"]
}
EOF

Get Policy token

$ vault token create -field token -policy=my-policy

Test Policy in SSH client machine

  • Using token in SSH client
$ export VAULT_TOKEN="<policy_token>"
$ vault write -field=signed_key ssh-client-signer/sign/my-role public_key=@$HOME/.ssh/id_rsa.pub > signed-cert.pub
  • SSH into target system using signed public key and private key in SSH client
ssh -i signed-cert.pub -i ~/.ssh/id_rsa ubuntu@host

Enable approle

vault auth enable approle

Create role

vault write auth/approle/role/my-role \
    secret_id_ttl=10m \
    token_num_uses=10 \
    token_ttl=20m \
    token_max_ttl=30m \
    secret_id_num_uses=40 \
    token_policies=my-policy

Get role_id and secret_id

vault read -field=role_id auth/approle/role/my-role/role-id
vault write -f -field=secret_id auth/approle/role/my-role/secret-id

Login from SSH client machine

export VAULT_ADDR='http://host:8200'
export ROLE_ID=<role_id>
export SECRET_ID=<secret_id>
vault write auth/approle/login role_id="$ROLE_ID" secret_id="$SECRET_ID"

Result contains token

Key                     Value
---                     -----
token                   s.Sh9h1wZ9ycATeSaASoOQvovr
...

Check the token info

vault token lookup | grep policies
policies            [default my-policy]

Test Policy in SSH client machine

  • Using token in SSH client
$ export VAULT_TOKEN="<policy_token>"
$ vault write -field=signed_key ssh-client-signer/sign/my-role public_key=@$HOME/.ssh/id_rsa.pub > signed-cert.pub
  • SSH into target system using signed public key and private key in SSH client
ssh -i signed-cert.pub -i ~/.ssh/id_rsa ubuntu@host

Consideration

Disable password authentication

If tested finished, password authentication can be set to no:

PasswordAuthentication no

Time valid for SECRET_ID

If the secret_id expires so fast, then needs to have master token to generate secret_id again, because the policy token is generated using role_id and secret_id pair.

If don't use approle, then all SSH clients can use policy token. Still thinking the advantage of using role_id and secret_id.

Use admin token instead

The root token should not be used as recommended. Will try admin token later.

References

Policies

Install brew in MacOS 10.13.6

Install brew in MacOS 10.13.6

Steps

Download following packages, install first two packages.

Xcode_10.1.xip
Command_Line_Tools_macOS_10.13_for_Xcode_10.1.dmg
Kernel_Debug_Kit_10.13.6_build_17G10017.dmg
Swift_5_Runtime_Support_for_Command_Line_Tools.dmg
Swift_Playgrounds_Author_Template_for_Xcode_10.xip
Font_Tools_for_Xcode_11.dmg
Additional_Tools_for_Xcode_10.1.dmg

Run following command to install

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

References

All Downloads
Install Homebrew · Mac M1

Signed SSH Certificates using Hashicorp Vault

Signed SSH Certificates using Hashicorp Vault

The idear of signed SSH certificates verification is to use valid (signed) SSH certificate to be verified by SSH server or by SSH client, or by both.

Mechanism

Vaildated by SSH server

Client retrieves signed public key which issued by the CA key in Vault. This key has short expiry date.

Server uses the CA public key configured in SSH configuration, validates the client public key issued by Vault.

Validated by SSH client

This is to validate server public whether signed by Vault by place public key in .ssh/known_hosts file. This key should have long expiry date.

Steps

Vault Server preparation

  • Login into Vault
export VAULT_ADDR='http://127.0.0.1:8200'
export VAULT_TOKEN="<token>"
  • Enable SSH secret engine
$ vault secrets enable -path=ssh-client-signer ssh
Successfully mounted 'ssh' at 'ssh-client-signer'!
  • Configure CA
$ vault write ssh-client-signer/config/ca generate_signing_key=true
Key             Value
---             -----
public_key      ssh-rsa AAAAB3NzaC1yc2EA...
  • Create Role

Beware of *allowed_users" and "default_user", they must be set correctly.

$ vault write ssh-client-signer/roles/my-role -<<"EOH"
{
  "allow_user_certificates": true,
  "allowed_users": "*",
  "allowed_extensions": "permit-pty,permit-port-forwarding",
  "default_extensions": [
    {
      "permit-pty": ""
    }
  ],
  "key_type": "ca",
  "default_user": "ubuntu",
  "ttl": "30m0s"
}
EOH

SSH Server Setup

  • Login to Vault
export VAULT_ADDR='http://127.0.0.1:8200'
export VAULT_TOKEN="<token>"
  • Save CA key
# vault read -field=public_key ssh-client-signer/config/ca > /etc/ssh/trusted-user-ca-keys.pem
  • Configure SSHD

Add following lines in /etc/ssh/sshd_config

TrustedUserCAKeys /etc/ssh/trusted-user-ca-keys.pem
  • Restart SSHD
# systemctl restart sshd

SSH Client

  • Generate SSH key pair if haven't done
$ ssh-keygen -t rsa -C "user@example.com"

This will generate a pair of files, .ssh/id_rsa and .ssh/id_rsa.pub.

  • Generate and save signed public key using client public key
$ vault write -field=signed_key ssh-client-signer/sign/my-role \
    public_key=@$HOME/.ssh/id_rsa.pub > signed-cert.pub
  • Verify signed key (optional)

This can verify the valid period and user

$ ssh-keygen -Lf ~/.ssh/signed-cert.pub
...
        Valid: from 2021-11-27T17:51:29 to 2021-11-27T18:21:59
        Principals: 
                ubuntu
...
  • Login to server using both signed key and private key
$ ssh -i signed-cert.pub -i ~/.ssh/id_rsa username@10.0.23.5

Note: Add following configure in /etc/ssh/sshd_config if got error __userauth_pubkey: certificate signature algorithm ssh-rsa: signature algorithm not supported [preauth]__

CASignatureAlgorithms ^ssh-rsa

References

Signed SSH Certificates
Leveraging Signed SSH for Remote Access with Vault

Hashicorp Vault docker installation and client testing

Hashicorp Vault docker installation and client testing

Vault Server Installation

Create one folder with 3 subfolders

mkdir -p vault/{config,file,logs}

Create vault configuration file

Create vault/config/vault.json

{
  "backend": {
    "file": {
      "path": "/vault/file"
    }
  },
  "listener": {
    "tcp":{
      "address": "0.0.0.0:8200",
      "tls_disable": 1
    }
  },
  "ui": true
}

Create docker-compose.yml

Create file vault/docker-compose.yml

version: '3.7'
services:
  vault:
    image: vault:latest
    container_name: vault
    ports:
      - "8200:8200"
    restart: unless-stopped
    volumes:
      -  ./logs:/vault/logs
      -  ./file:/vault/file
      -  ./config:/vault/config
    cap_add:
      - IPC_LOCK
    entrypoint: vault server -config=/vault/config/vault.json

Create container

Run docker-compose command in vault folder

cd vault
docker-compose up -d

Access WebUI

Access http://localhost:8200/ from browser

  • Select 5 as Key shares, and 3 as Key threshold, and Initialize
  • Download keys into a Json file
  • Use 3 keys to unseal vault
  • Use root token to login

Client installation

Ubuntu x86

  • Add the HashiCorp GPG key
# curl -fsSL https://apt.releases.hashicorp.com/gpg | apt-key add -
  • Add the official HashiCorp Linux repository
# apt-add-repository "deb [arch=amd64] https://apt.releases.hashicorp.com $(lsb_release -cs) main"
  • Install vault
# apt-get install vault
  • Verify
# vault

Connect to vault

  • Set environment
$ export VAULT_ADDR='http://127.0.0.1:8200'
$ export VAULT_TOKEN="<token>"
  • Check status
$ vault status
...
Sealed          false
...

Secrets operations

Subcommand kv v1 kv v2 Description
delete x x Delete versions of secrets stored in K/V
destroy x Permanently remove one or more versions of secrets
enable-versioning x Turns on versioning for an existing K/V v1 store
get x x Retrieve data
list x x List data or secrets
metadata x Interact with Vault\'s Key-Value storage
patch x Update secrets without overwriting existing secrets
put x x Sets or update secrets (this replaces existing secrets)
rollback x Rolls back to a previous version of secrets
undelete x Restore the deleted version of secrets

Example:

vault-getting-started:~# vault login root
Success! You are now authenticated. The token information displayed below
is already stored in the token helper. You do NOT need to run "vault login"
again. Future Vault requests will automatically use this token.

Key                  Value
---                  -----
token                root
token_accessor       rSn3h08ikdez4zch5ghr4wYY
token_duration       ∞
token_renewable      false
token_policies       ["root"]
identity_policies    []
policies             ["root"]
vault-getting-started:~# vault kv put secret/hello foo=world
Key              Value
---              -----
created_time     2021-11-25T06:15:45.332182013Z
deletion_time    n/a
destroyed        false
version          1
vault-getting-started:~# vault kv put secret/hello foo=world excited=yes
Key              Value
---              -----
created_time     2021-11-25T06:15:48.808651794Z
deletion_time    n/a
destroyed        false
version          2
vault-getting-started:~# vault kv get secret/hello
====== Metadata ======
Key              Value
---              -----
created_time     2021-11-25T06:15:48.808651794Z
deletion_time    n/a
destroyed        false
version          2

===== Data =====
Key        Value
---        -----
excited    yes
foo        world
vault-getting-started:~# vault kv get -field=excited secret/hello
yes
vault-getting-started:~# vault kv get -format=json secret/hello | jq -r .data.data.excited
yes
vault-getting-started:~# vault kv delete secret/hello
Success! Data deleted (if it existed) at: secret/hello
vault-getting-started:~#

Secret Engine

The driver to save secret in different way, type of secret.

List

Every path has it's own secret type

$ vault secrets list

Path          Type         Accessor              Description
----          ----         --------              -----------
cubbyhole/    cubbyhole    cubbyhole_78189996    per-token private secret storage
identity/     identity     identity_ac07951e     identity store
kv/           kv           kv_15087625           n/a
secret/       kv           kv_4b990c45           key/value secret storage
sys/          system       system_adff0898       system endpoints used for control, policy and debugging

Enable

Set one path to specific secret type

$ vault secrets enable -path=kv kv

Success! Enabled the kv secrets engine at: kv/

or

$ vault secrets enable kv

Create secret

$ vault kv put kv/hello target=world
Success! Data written to: kv/hello

Get secret

$ vault kv get kv/hello

===== Data =====
Key       Value
---       -----
target    world

Delete secret

$ vault kv delete kv/hello
Success! Data deleted (if it existed) at: kv/hello

List

$ vault kv list kv/

Keys
----
hello

Disable

$ vault secrets disable kv/

Success! Disabled the secrets engine (if it existed) at: kv/

Dynamic Secrets

When using secret engine such as aws engine.

$ vault secrets enable -path=aws aws

Success! Enabled the aws secrets engine at: aws/

More Info: Dynamic Secrets

Authentication

Token

  • Create token
$ vault token create
Key                  Value
---                  -----
token                s.iyNUhq8Ov4hIAx6snw5mB2nL
token_accessor       maMfHsZfwLB6fi18Zenj3qh6
token_duration       ∞
token_renewable      false
token_policies       ["root"]
identity_policies    []
policies             ["root"]
  • Login
$ vault login s.iyNUhq8Ov4hIAx6snw5mB2nL

Success! You are now authenticated. The token information displayed below
is already stored in the token helper. You do NOT need to run "vault login"
again. Future Vault requests will automatically use this token.

Key                  Value
---                  -----
token                s.iyNUhq8Ov4hIAx6snw5mB2nL
token_accessor       maMfHsZfwLB6fi18Zenj3qh6
token_duration       ∞
token_renewable      false
token_policies       ["root"]
identity_policies    []
policies             ["root"]
  • Revoke
$ vault token revoke s.iyNUhq8Ov4hIAx6snw5mB2nL

Success! Revoked token (if it existed)

GitHub

  • Enable
$ vault auth enable github

Success! Enabled github auth method at: github/
  • Set organization
$ vault write auth/github/config organization=hashicorp

Success! Data written to: auth/github/config
  • Configure the GitHub engineering team authentication to be granted the default and applications policies
$ vault write auth/github/map/teams/engineering value=default,applications

Success! Data written to: auth/github/map/teams/engineering
  • List
$ vault auth list

Path       Type      Description
----       ----      -----------
github/    github    n/a
token/     token     token based credentials
  • Set login method
$ vault login -method=github

GitHub Personal Access Token (will be hidden):
Success! You are now authenticated. The token information displayed below
is already stored in the token helper. You do NOT need to run "vault login"
again. Future Vault requests will automatically use this token.

Key                    Value
---                    -----
token                  s.DNtKCjVQ1TxAzgMqtDuwjjC2
token_accessor         e7zLJuPg2tLpav66ZSu5AyDC
token_duration         768h
token_renewable        true
token_policies         [default applications]
token_meta_org         hashicorp
token_meta_username    my-user
  • Login
$ vault login root
  • Revoke all tokens generated the github auth method
$ vault token revoke -mode path auth/github
  • Disable the github auth method
$ vault auth disable github

Success! Disabled the auth method (if it existed) at: github/

Policy

  • Policy for token

The policy path secret/data/* is related to all secret path secret/*.
The policy path secret/data/foo is related to secret path secret/foo.

  • Policy for approle

The policy path secret/approle/* is related to role_id + secret_id authentication.

Policy for token

  • Create
$ vault policy write my-policy - << EOF
# Dev servers have version 2 of KV secrets engine mounted by default, so will
# need these paths to grant permissions:
path "secret/data/*" {
  capabilities = ["create", "update"]
}

path "secret/data/foo" {
  capabilities = ["read"]
}
EOF
  • List
$ vault policy list

default
my-policy
root
  • Show
$ vault policy read my-policy

# Dev servers have version 2 of KV secrets engine mounted by default, so will
# need these paths to grant permissions:
path "secret/data/*" {
  capabilities = ["create", "update"]
}

path "secret/data/foo" {
  capabilities = ["read"]
}
  • Create token
$ export VAULT_TOKEN="$(vault token create -field token -policy=my-policy)"
  • Check policy
$ vault token lookup | grep policies
policies            [default my-policy]
  • Write success
$ vault kv put secret/creds password="my-long-password"

Key              Value
---              -----
created_time     2018-05-22T18:05:42.537496856Z
deletion_time    n/a
destroyed        false
version          1
  • Write failed
$ vault kv put secret/foo robot=beepboop

Error writing data to secret/data/foo: Error making API request.

URL: PUT http://localhost:8200/v1/secret/data/foo
Code: 403. Errors:

* 1 error occurred:
  * permission denied

Policy for approle

  • Enable
$ vault auth enable approle
Success! Enabled approle auth method at: approle/
  • Create my-role link to my-policy
$ vault write auth/approle/role/my-role \
    secret_id_ttl=10m \
    token_num_uses=10 \
    token_ttl=20m \
    token_max_ttl=30m \
    secret_id_num_uses=40 \
    token_policies=my-policy
Success! Data written to: auth/approle/role/my-role
  • Create role_id
$ export ROLE_ID="$(vault read -field=role_id auth/approle/role/my-role/role-id)"
  • Create secret_id
$ export SECRET_ID="$(vault write -f -field=secret_id auth/approle/role/my-role/secret-id)"
  • Login
$ vault write auth/approle/login role_id="$ROLE_ID" secret_id="$SECRET_ID"
Key                     Value
---                     -----
token                   s.Sh9h1wZ9ycATeSaASoOQvovr
token_accessor          xCgUIu6WWLM9opkEkAiNLsRc
token_duration          20m
token_renewable         true
token_policies          ["default" "my-policy"]
identity_policies       []
policies                ["default" "my-policy"]
token_meta_role_name    my-role

References

vault-docker
Install Vault

NextCloud menu display incorrectly

NextCloud menu display incorrectly

A strange error happens in some browsers, NextCloud menu become a big page vertically, and one password textbox there requesting password, but the password is not working.

Not specific OS or browser

In my iMac, Safari is not working. In my one Windows machine, Firefox is not working. By the way, the Firefox has sync enabled and it is working in another PC. Google Chrome and Microsoft Edge have no issue.

Debugging

There is programming error, the contents were downloaded from following website directly, not the NextCloud server. Browser blocked them.

https://raw.githubusercontent.com

Solution

Disable "Theming App" in NextCloud Apps screen.

References

NextCloud page not displaying correctly

The `sed` command uncommon behaviors

The sed command uncommon behaviors

The sed command is used in Unix, some strange behaviors can let time waste.

Escape char in regex

Normally, the \ is escape character, but it wasn't in some cases.

For example, . is to match any character, it needs to have \ as escape character if need it to be a dot character.

$ echo "test (111) help . 1" | sed -e "s/.//"
est (111) help . 1
$ echo "test (111) help . 1" | sed -e "s/\.//"
test (111) help  1

But this is not for (), without \, they are (), with \, they are indicating subpattern.

$ echo "test (111) help . 1" | sed -e 's/(111)//'
test  help . 1
$ echo "test (111) help . 1" | sed -e 's/\(111\)//'
test () help . 1
$ 

Same for {}

echo "test (111) help . 1" | sed -e 's/hel{1}p//'
test (111) help . 1
$ echo "test (111) help . 1" | sed -e 's/hel\{1\}p//'
test (111)  . 1

and ?

$ echo "test (111) help . 1" | sed -e 's/he?lp//'
test (111) help . 1
$ echo "test (111) help . 1" | sed -e 's/h?lp//'
test (111) help . 1
$ echo "test (111) help . 1" | sed -e 's/he\?lp//'
test (111)  . 1

* and +

The sed understands the meaning of *, but not for +.

$ echo "test (111) help . 1" | sed -e 's/hel*p//'
test (111)  . 1
$ echo "test (111) help . 1" | sed -e 's/hel+p//'
test (111) help . 1

\* and \+

The sed understands the meaning of \+, but not for \*.

$ echo "test (111) help . 1" | sed -e 's/hel\*p//'
test (111) help . 1
$ echo "test (111) help . 1" | sed -e 's/hel\+p//'
test (111)  . 1

Install App in NextCloud Manually

Install App in NextCloud Manually

Got issue to see AppStore in NextCloud, could not fix it.

Tried, but failed

Set appstore in config.php

Updated config.php with following options, but failed.

'appstoreenabled' => true,
'appstoreurl' => 'https://apps.nextcloud.com/api/v1',

But successfully using curl tested access to https://apps.nextcloud.com/api/v1.

Using occ

php occ app:list

Can not see Apps in AppStore

Manual installation

  • Download App from app.nextcloud.com, extract to nextcloud/apps folder.

  • Change owner to www-data:www-data

  • Go to GUI Apps => Disabled apps, refresh page

  • Then the app should be listed.

  • Click on install to install it.

References

Apps management
Using the occ command

Disable ICMPv6 Redirect Messages in Solaris

Disable ICMPv6 Redirect Messages in Solaris

As CIS requirements, ICMPv6 Redirect Messages should be disabled in Solaris.

Steps

Download two following files

cis_netconfig.sh
cis_netconfig.xml

Following commands are copied from CIS document, which is not clean. Just for reference.

cat > cis_netconfig.sh << END
#!/sbin/sh
ndd -set /dev/ip ip_forward_src_routed 0
ndd -set /dev/ip ip6_forward_src_routed 0
ndd -set /dev/tcp tcp_rev_src_routes 0
ndd -set /dev/ip ip_forward_directed_broadcasts 0
ndd -set /dev/tcp tcp_conn_req_max_q0 4096
ndd -set /dev/tcp tcp_conn_req_max_q 1024
ndd -set /dev/ip ip_respond_to_timestamp 0
ndd -set /dev/ip ip_respond_to_timestamp_broadcast 0
ndd -set /dev/ip ip_respond_to_address_mask_broadcast 0
ndd -set /dev/ip ip_respond_to_echo_multicast 0
ndd -set /dev/ip ip6_respond_to_echo_multicast 0
ndd -set /dev/ip ip_respond_to_echo_broadcast 0
ndd -set /dev/arp arp_cleanup_interval 60000
ndd -set /dev/ip ip_ire_arp_interval 60000
ndd -set /dev/ip ip_ignore_redirect 1
ndd -set /dev/ip ip6_ignore_redirect 1
ndd -set /dev/tcp tcp_extra_priv_ports_add 6112
ndd -set /dev/ip ip_strict_dst_multihoming 1
ndd -set /dev/ip ip6_strict_dst_multihoming 1
ndd -set /dev/ip ip_send_redirects 0
ndd -set /dev/ip ip6_send_redirects 0
END
chmod +x cis_netconfig.sh
cat > cis_netconfig.xml << END
<?xml version="1.0"?>
<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
<service_bundle type='manifest' name='CIS:cis_netconfig'>
  <service name='site/cis_netconfig' type='service' version='1'>
    <create_default_instance enabled='true' />
    <single_instance />

    <dependency name='usr' type='service' grouping='require_all' restart_on='none'>
      <service_fmri value='svc:/system/filesystem/minimal' />
    </dependency>

    <!-- Run ndd commands after network/physical is plumbed. -->
    <dependency name='network-physical' grouping='require_all' restart_on='none' type='service'>
      <service_fmri value='svc:/network/physical' />
    </dependency>

    <!-- but run the commands before network/initial -->
    <dependent name='ndd_network- initial' grouping='optional_all' restart_on='none'>
      <service_fmri value='svc:/network/initial' />
    </dependent>

    <exec_method type='method' name='start' exec='/lib/svc/method/cis_netconfig.sh' timeout_seconds='60' />
    <exec_method type='method' name='stop' exec=':true' timeout_seconds='60' />
    <property_group name='startd' type='framework'>
       <propval name='duration' type='astring' value='transient' />
    </property_group>

    <stability value='Unstable' />
    <template>
      <common_name>
        <loctext xml:lang='C'> CIS IP Network Parameter Set </loctext>
      </common_name>
    </template>
  </service>
</service_bundle>
END
cp cis_netconfig.sh /lib/svc/method
chmod 750 /lib/svc/method/cis_netconfig.sh
svccfg import cis_netconfig.xml

Create a service

# cp cis_netconfig.sh /lib/svc/method
# chmod 750 /lib/svc/method/cis_netconfig.sh
# svccfg import cis_netconfig.xml

References

CIS Oracle Solaris 10 Benchmark v5.2.0 - 09-02-2015 - Local Cache

Split NGINX configuration file

Split NGINX configuration file

To split NGINX configuration file into multiple conf.d/*.conf files.

This is defined in /etc/nginx/nginx.conf file as below

http {
    ...
    include /etc/nginx/conf.d/*.conf;
}

Pros

Avoid large configuration file and manage easiler.

NGINX will read all files in conf.d directory, which has extension name as .conf and use them all as final configuration.

Cons

Only definitions in http { ... } directive can be defined in conf.d/*.conf.

Which file to be loaded first is unclear.

One server definition should not be defined in mulitipe files.