1Password AWS Credentials

1Password CLI 2 offers a way to use AWS credentials with the AWS CLI. However, you have to create shell aliases for all the commands you want to use with with. A better solution would be to let the AWS CLI/SDK lookup the credentials itself in 1Password. Luckily, the AWS config supports this with credential_process!

Requirements to make this work:

  • AWS CLI v2. It might work with v1 but I did not test it.
  • 1Password items with these fields:
    • access key id or access_key_id
    • secret access key or secret_access_key
  • 1Password CLI 2 which can authenticate to your vault.
  • My op-aws-credentials.py script in a conveinent location (/usr/local/bin).

When you have those things in place, you can modify your ~/.aws/config file:

[default]
credential_process = /opt/local/bin/op-aws-credentials.py --vault AWS --item default

[profile1]
credential_process = /opt/local/bin/op-aws-credentials.py --vault AWS --item profile1

[profiloe2]
credential_process = /opt/local/bin/op-aws-credentials.py --vault AWS --item profile2

Then delete the lines from your ~/.aws/credentials file. This example assume you have a vault called “AWS” with items in it “default”, “profile1”, and “profile2”.

I’ve tested this with the AWS CLI v2, terraform 1.2.2, and some boto3 scripts (which is 95% of my CLI usage).

Gentoo Gateway/Router, Comcast, & IPv6

After many attempts and stumbles, I’ve finally been able to get my home network setup with IPv6 on Comcast. Many thanks to this Native IPv6 on Comcast article; I used it as my starting point to building the network I wanted.

The Goal

My IPv4 setup is your standard NAT where the gateway machine holds the external IP. Comcast will give you an IPv6 prefix, and I wanted to use that for the internal network instead of NAT. The goal is to have an IPv6 address bound to my external interface, and an IPv6 prefix advertised on my internal network for stateless configuration.

The Setup

Before I get into the details, I have a few notes to share about my setup.

Gentoo Linux: the Linux for tinkerers, which also means this was all a little more difficult than it should have been (but that’s the way I like it). If you’re using another distribution then you won’t be able to follow this guide step-by-step. But hopefully parts of it will still be useful.

Interface Names: my instructions and scripts will refer to two interface names: ethwan and brint. My external interface is ethwan and is a physical device. My internal interface is brint (for bridged internal) and is a bridge of my two internal interfaces (ethwlan and ethlan). You’ll have to change the scripts to match your interface names.

iproute2: Many of the scripts assume you’re using the iproute2 package.

Kernel 3.14: I spent a lot of time scratching my head because directions I found on the internet just weren’t working. I think it’s because of subtle changes in the 3.x kernel that made advice for 2.6 kernels obsolete. YMMV.

Getting the IPv6 Address

First thing we need to do is get an IPv6 address allocated to ethwan. For the longest time I’ve used the dhcpcd package, but I found dhclient worked much better for IPv6. Unfortunately, Gentoo doesn’t provide the right netifrc modules to support both DHCPv4 and DHCPv6 on the same interface. Starting with the existing dhclient module, I modified it to support DHCPv6: /lib64/netifrc/net/dhclientv6.sh

Now setup your /etc/conf.d/net configuration to use both:

modules="dhclient
         dhclientv6"

config_ethwan="dhcp
               dhcpv6"
dhcp_ethwan="release nodns nontp nonis nosendhost"
dhcpv6_ethwan="release nodns nontp nonis nosendhost"
dhclientv6_ethwan="-P"
rc_net_ethwan_after="net.brint"

Couple notes:

  • I run my own DNS, hence the “nodns”. You might not want this option.
  • Ibid with NTP: “nontp”.
  • The argument for dhclientv6 of “-P” tells it to request the prefix we’ll use for the internal network.
  • The scripts need brint started, so start ethwan after it.
  • For a long time, my MTU was set to 576. This is far to small for IPv6, and you’ll get a cryptic error when dhclient tries to assign an address. Increase it to 1500.

Restarting ethwan should now give you an IPv6 address! Launch a browser on the gateway and test it.

Assigning the Prefix

Having the prefix isn’t enough. You also have to setup forwarding in the kernel, accept router announcements from the cable modem, add a routing table entry, and start advertising the prefix to the internal network.

Complicating things is that the prefix could change at any time. But there is a way to automate all the configuration changes and make sure the internal network always stays current.

Next we’re going to write a hook for dhclient that runs whenever our prefix changes and adjusted the settings appropriately. It does this by looking at environment variables that dhclient passes to dhclient-script, which will then call our script.

The packaged dhclient-script will check for /etc/dhcp/dhclient-exit-hooks and sources that. Lots of distributions provide the /etc script, but not Gentoo. No worries, it’s easy to write our own dhclient-exit-hooks:

#!/bin/bash

if [ -d /etc/dhcp/dhclient-exit-hooks.d ]; then
	for f in /etc/dhcp/dhclient-exit-hooks.d/*.sh ; do
		if [ -x ${f} ]; then
			"${f}"
		fi
	done
fi

Important: my version of this script executes the hooks in /etc/dhcp/dhclient-exit-hooks.d. I did this so that I could use bash in my script, and not deal with the abomination that is sh syntax. If your distribution sources the individual hooks, then you’ll have to either adjust your dhclient-exit-hooks script, or adjust the next script that sets up the prefix.

The main script is /etc/dhcp/dhclient-exit-hooks.d/ipv6.sh. At the very least you will need to adjust the variables at the start. A couple notes:

  • It starts, stops, and checks radvd by running /etc/init.d/radvd. Other systems manage services other ways; adjust accordingly.
  • This will only run radvd when it thinks a prefix is defined. You should not set radvd to start with your system; the script will completely manage it.
  • It turns IPv6 forwarding on for all interfaces, and accept_ra to “2” for ethwan. I’ve found that on a 3.14 kernel, forwarding only works if enabled this way. If you don’t want forwarding for all interfaces, you can use iptables to block it.

Configuring radvd

The ipv6.sh script looks for a template file in the same directory as the configuration: radvd.conf.template. It will replace “__PREFIX__” with the DHCPv6 assigned prefix. Mine contains this:

interface brint {
        AdvSendAdvert on;
        MaxRtrAdvInterval 300;

        RDNSS fd11:2233:4455:1::1 { };
        DNSSL example.org { };

        prefix __PREFIX__ {
                AdvOnLink on;
                AdvAutonomous on;
        };

        prefix fd11:2233:4455:1::/64 {
                AdvOnLink on;
                AdvAutonomous on;
        };
};

This is setup for stateless configuration, which is the only way OS X and iOS devices work. If you’d like to use DHCPd then the process would be similar.

I’ve also registered a Unique Local Address prefix for my internal network. No, it’s not “fd11:2233:4455::”. I use this for contacting internal services on IPv6 since the Comcast prefix isn’t stable. The “prefix” line for this space advertises it to the internal network, for stateless configuration.

Since I run my own internal DNS, I put the IPv6 address of the server in my radvd.conf. If you don’t have one then leave the RDNSS and DNSSL lines out.

Also configure radvd to not touch the kernel forwarding setting since we do this in the ipv6.sh script. On Gentoo, it’s in /etc/conf.d/radvd, setting: FORWARD=”no”

Troubleshoot

Within a short period your internal devices should get an IPv6 address. With Comcast, the address assigned to ethwan and the prefix we advertise on brint are entirely different. No worries; this is expected!

You might also notice that unlike previous instructions, brint does not have an address allocated from the prefix. This is not required, all it needs is the routing table entry. Routing of packets from internal devices to the internet happens using the link-local addresses.

On an internal device, test your connection again. You can also use ping6 to contact “www.kame.net” or “ipv6.google.com”.

Internal devices are not getting an address. Make sure IPv6 is enabled on your device and set for automatic configuration. Check the logs for radvd and make sure it is running and advertising the right prefix on the right interface. You can run it in debug mode as: “radvd -d 5 -m stderr”.

Internal devices have an address but can’t contact services. Make sure the routing entry is set on brint. Make sure forwarding is set on all interfaces: “sysctl net.ipv6.conf.all.forwarding”.

Gateway gets an address but can’t contact services. Make sure that it is accepting routing advertisements on ethwan: “sysctl net.ipv6.conf.ethwan.accept_ra”. This must be set to “2” because Linux will ignore a setting of “1” if forwarding is also set. Check that the routing table has as its default IPv6 route the link-local address of the cable modem (should happen automatically).

Shibboleth and FERPA Suppression

Note: this document is still being revised as I explore the issue.

Many of the applications I support use Shibboleth not only for authentication, but also to populate and synchronize metadata about the user: display name, UIN, group memberships, or anything else available in our central registry. An upcoming change in how FERPA suppressed users are presented got me looking at how I could better use the Shibboleth Native Service Provider (SP) to handle metadata (I won’t be considering other SP’s).

Some of the attributes I request are only for convenience and are not mandatory for the application. When a user requests FERPA suppression the application should only have access to the smallest set of attributes required. One way to do this would be to modify each application to behave differently under suppression. But you can also use the Shibboleth SP itself to filter attributes, and leave the application alone.

At the University of Illinois, FERPA suppression is indicated in the iTrustSuppress attribute. If your SP isn’t already requesting this attribute, log in to the I-Trust Federation Registry and add it. We also have to configure the SP to map this attribute to a name in attribute-map.xml

<Attribute name="urn:oid:1.3.6.1.4.1.11483.101.3"id="iTrustSuppress"/>

You can check that the new attribute is being delivered by visiting “https://your-server.illinois.edu/Shibboleth.sso/Login?target=https://your-server.illinois.edu/Shibboleth.sso/Session”. If you’d like to see the attribute values, edit your shibboleth2.xml and set the “Session” handler “showAttributeValues” to “true”.

The last step is to edit attribute-policy.xml and define an iTrustSuppress policy. What attributes you allow or deny will depend on your applications, but here is an example of minimal attributes for WordPress (eppn and mail).

<afp:AttributeFilterPolicy id="iTrustSuppressPolicy">
    <!-- Only run this policy if the user is suppressed -->
    <afp:PolicyRequirementRule xsi:type="AttributeValueString"
            attributeID="iTrustSuppress"
            value="y"
            ignoreCase="true"/>

    <!--
        Rules for attributes we should always allow the application to see.
        This will vary based on the requirements of the application.

        * eppn: used for REMOTE_USER
        * mail: required by WordPress for all users
        * persistent-id: unused, but not identifiable information
    -->
    <afp:AttributeRule attributeID="eppn">
        <afp:PermitValueRule xsi:type="ANY"/>
    </afp:AttributeRule>
    <afp:AttributeRule attributeID="mail">
        <afp:PermitValueRule xsi:type="ANY"/>
    </afp:AttributeRule>
    <afp:AttributeRule attributeID="persistent-id">
        <afp:PermitValueRule xsi:type="ANY"/>
    </afp:AttributeRule>


    <!--
        Attributes allowed by another filter policy,
        but should be FERPA supressed. If they are explicitly allowed
        by any non-wildcard filter policy then the wildcard rule
        will not run.
    -->
    <afp:AttributeRule attributeID="affiliation">
        <afp:DenyValueRule xsi:type="ANY"/>
    </afp:AttributeRule>
    <afp:AttributeRule attributeID="unscoped-affiliation">
        <afp:DenyValueRule xsi:type="ANY"/>
    </afp:AttributeRule>
    <afp:AttributeRule attributeID="primary-affiliation">
        <afp:DenyValueRule xsi:type="ANY"/>
    </afp:AttributeRule>

    <!--
        Default rule is to suppress the value. This wildcard
        rule will not run if the attribute matches any non-wildcard
        rules in other policies.
    -->
    <afp:AttributeRule attributeID="*">
        <afp:DenyValueRule xsi:type="ANY"/>
    </afp:AttributeRule>
</afp:AttributeFilterPolicy>Test

If you have other policies defined then make sure that any attributes they explicitly allow should be allowed for a suppressed user, or are explicitly denied in the iTrustSuppressPolicy. Filter policies are evaluated in the order they are defined, so it would probably be best to add the iTrustSuppressPolicy at the end of the filter policy group.