Skip to main content

InstanceCredentials

Struct InstanceCredentials 

Source
pub struct InstanceCredentials {
    fetch: Box<dyn CredentialFetch>,
    held: Mutex<TimedCredentials>,
}
Expand description

The credential every Route53 request in this process is signed with, kept current against the instance profile that issues it.

An instance profile’s credential is temporary: IMDS states an Expiration, and a signature made with a credential past it is rejected by Route53 — which on this deployment stops agent hostnames being published and stops ACME DNS-01 renewing the certificate, since terraform-aws-didbot-pds/security_groups.tf opens no port 80 for an HTTP-01 order. This holder reads IMDS again once the credential it holds is within REFRESH_MARGIN of that expiry, and hands out the new one.

A refresh that fails is reported at error and tried again on the next request rather than ending the process: while the credential in hand is still valid it keeps signing with it, and once it is not, Self::current returns the ImdsError, which reaches a caller as a DnsError::Backend through the same retry path as any other transport failure.

The refresh happens under the lock on the held credential, so callers that arrive during one wait for it and then sign with what it produced: a hosted zone being written by several threads makes one IMDS read between them, not one each.

Fields§

§fetch: Box<dyn CredentialFetch>§held: Mutex<TimedCredentials>

Implementations§

Source§

impl InstanceCredentials

Source

pub fn from_instance_metadata() -> Result<Self, ImdsError>

Reads the credential of whatever IAM role is attached to this EC2 instance, over IMDSv2, and keeps reading it as it expires.

IMDSv2 specifically, not v1: v1’s tokenless GET is what let the 2019 Capital One breach turn an unrelated request-smuggling bug into stolen instance-role credentials, and infra/pds/’s launch template requires the token hop (HttpTokens = required) for exactly that reason — see docs/deployment.md. This is the one credential path this crate offers a production deployment: there is no environment variable or file this reads instead, because inventing a second path is a second thing to misconfigure and a second place a credential can leak from.

Three round trips, each against a 5-second timeout: the session token, the attached role’s name, and that role’s current credentials. Blocking, like the rest of this provider — see the module docs for why. The first read happens here, so a deployment whose instance profile is wrong fails at startup rather than at the first publish.

Source

pub(crate) fn with_fetch( fetch: Box<dyn CredentialFetch>, ) -> Result<Self, ImdsError>

Source

pub fn current(&self) -> Result<Route53Credentials, ImdsError>

The credential to sign the next request with, refreshed first if the one held is inside REFRESH_MARGIN of its expiry.

Source§

impl InstanceCredentials

The one lever crate::aws_fake has on a credential holder that is otherwise driven entirely by the wall clock.

Nothing outside this crate’s own tests can reach it: it is pub(crate) and behind the aws-fake feature, which no production build turns on.

Source

pub(crate) fn expire_held(&self)

Makes the credential in hand expired as of now, so the next Self::current takes the refresh path rather than answering from what it holds.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

§

impl<T> PolicyExt for T
where T: ?Sized,

§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns [Action::Follow] only if self and other return Action::Follow. Read more
§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns [Action::Follow] if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more