skip to content

Delegation and Forwarding

Letting a service act as the user: forwardable tickets, unconstrained versus constrained delegation, and the S4U2Self and S4U2Proxy extensions. Asked because one wrong setting gives away the realm.

on this pageshow

explore

questions

4

In Kerberos, what does the forwardable(1) ticket flag permit that proxiable(3) does not?

level: middleimportance: must knowfreq 48%

answer

  1. two bits, two blast radii
  2. one buys a ticket, one buys all
  3. requested as an option, seen as a flag
  4. proxiable yields proxy(4), forwardable yields forwarded(2)
  5. a forwarded ticket-granting ticket is the user

basics

~20 s

forwardable(1) lets the ticket-granting service mint a new ticket-granting ticket for the holder; proxiable(3) only lets it mint single service tickets. A forwarded ticket-granting ticket buys tickets to anything in the realm; a proxy ticket buys nothing more.

solid answer

~40 s

Both bits are requested as KDC options in the `KDC-REQ-BODY` and appear in the issued ticket's `TicketFlags`, and both exist so a middle tier can act on the user's behalf — but they differ in what the ticket-granting service may then hand out. `proxiable(3)` on a ticket-granting ticket tells the ticket-granting service it may issue an ordinary service ticket, marked `proxy(4)`, possibly with different network addresses in `caddr`; the requester names the target service, so the grant is one ticket wide. `forwardable(1)` additionally permits a *new ticket-granting ticket*, marked `forwarded(2)`. A service holding that forwarded ticket-granting ticket is for practical purposes the user: it can present it to the ticket-granting service and obtain a service ticket to any registered service principal in the realm, repeatedly, with no further approval.

code

asn1 · 17 lines
asn1
TicketFlags ::= KerberosFlags
    -- reserved(0),
    -- forwardable(1),
    -- forwarded(2),
    -- proxiable(3),
    -- proxy(4),
    -- may-postdate(5),
    -- postdated(6),
    -- invalid(7),
    -- renewable(8),
    -- initial(9),
    -- pre-authent(10)

KDCOptions ::= KerberosFlags
    -- the client ASKS here, in KDC-REQ-BODY;
    -- bit positions 1..4 carry the same four names,
    -- and the KDC decides which of them it grants

go deeper

for a junior

Recall that a Kerberos ticket carries flags, and that two of them decide whether anyone but the original client may go on using the credential. Know that a ticket-granting ticket is the credential that buys other tickets.

for a middle

Explain the mechanics: the client requests the bit as a KDC option, the KDC grants it, and it appears in the issued ticket's TicketFlags. Say precisely what the ticket-granting service may issue under each bit.

for a senior

Show you know the reach difference is the whole point, and that a forwarded ticket-granting ticket is opaque to its holder yet fully spendable. Be able to say why the bit cannot be added after issuance.

for a principal

Frame it as a reach decision made once, at first issuance, for a credential you will not see again. Argue for or against permitting forwarding at all across an estate before arguing about individual services.

## The flags, and where they actually live Every Kerberos ticket carries a bit string called `TicketFlags` inside its `EncTicketPart` — the encrypted half that only the principal named by `sname`/`srealm` can open. Four of those bits exist purely to say whether, and how far, a party other than the original client may go on using the credential: - **`forwardable(1)`** — the ticket-granting service may issue a *further ticket-granting ticket* derived from this one. - **`forwarded(2)`** — set on a ticket that was issued that way, so anyone reading the ticket can see it did not come straight from the client. - **`proxiable(3)`** — the ticket-granting service may issue a *service ticket*, but not a ticket-granting ticket, derived from this one. - **`proxy(4)`** — set on a service ticket that was issued that way. A client does not set these bits. It **asks** for them as KDC options in the `KDC-REQ-BODY` of an `AS-REQ` or a `TGS-REQ`, at the same bit positions; the KDC decides whether to grant them, and the granted bit then shows up in the issued ticket's `TicketFlags`. Requested in one message, observed in another — which is why the bare word *flag* is ambiguous even inside this one protocol. One consequence worth stating early: **`forwardable(1)` has to be present from the start**. It is granted when the ticket-granting ticket is first issued, in the `AS-REP`. No later `TGS-REQ` can add a bit the original ticket does not carry. ## What each one permits, side by side | | `proxiable(3)` | `forwardable(1)` | |---|---|---| | What the ticket-granting service may issue from it | one service ticket, marked `proxy(4)` | a further ticket-granting ticket, marked `forwarded(2)` | | Who names the target | the requester, at request time | nobody — the holder chooses later, as often as it likes | | Network addresses | the new ticket may carry different `caddr` values | the new ticket may carry different `caddr` values | | Reach of what is handed over | one service principal | every service principal the ticket-granting service will serve | | How it ends | that one ticket expires | the forwarded ticket-granting ticket's whole lifetime, `renew-till` included | The row that matters is the fourth. `proxiable(3)` is a *scoped* grant whose scope was fixed by whoever asked for it. `forwardable(1)` is an *unscoped* one, because a ticket-granting ticket is precisely the credential that buys other credentials. ## Why an acceptor holding a forwarded ticket-granting ticket is the user Walk the sequence the holder can run: 1. Present the forwarded ticket-granting ticket in a `TGS-REQ`, as `pa-tgs-req (padata-type 1)`, together with an `Authenticator` keyed with the session key that came with it. 2. Name any service principal it likes in the request body. 3. Receive a `TGS-REP` carrying a service ticket whose `cname` and `crealm` are **the user's**, not the holder's. 4. Go back to step 1 for as long as the forwarded ticket-granting ticket is valid. Nothing in that loop consults the user again, and nothing in it consults the back-end service either. That is the entire reason the choice between these two bits is treated as a security decision rather than a convenience one. ## What the holder can and cannot see - The forwarded ticket-granting ticket is sealed under the **`krbtgt` key**, so the holder **cannot read it** — the client name, flags, `authtime` and `renew-till` inside `enc-part` are opaque to it. - It arrives **with its session key**, supplied out of band by the delegating client, so the holder **can spend it** without ever reading it. - Being unable to read a credential is not a limit on using it. This is the single most common confusion on the subject: opacity protects the KDC's integrity, not the user. - `proxy(4)`, by contrast, is informational at the far end: an application service that cares can notice the ticket did not come directly from the original client's host and refuse it. ## Where the two bits sit relative to the delegation models `forwardable(1)` is the mechanism underneath **unconstrained forwarding**: the client's own credential travels, and the realm is the limit. The later delegation models — where a middle tier is restricted to a named list of target services, or where the target service itself declares who may impersonate to it — exist to give the useful half of forwarding without that reach. `proxiable(3)` is the older and much narrower answer to the same need, and is comparatively rarely deployed, because naming the target at request time is exactly what the middle tier usually cannot do in advance.

  • Can a service holding a forwarded ticket-granting ticket forward it again to a fourth service?
    Only if the forwarded ticket itself carries `forwardable(1)`. The ticket-granting service applies the same rule at every hop: it issues a further ticket-granting ticket only from one whose `TicketFlags` already permit it. Issuing the forwarded ticket without that bit ends the chain after a single hop.
  • What does proxy(4) let an application service do that it could not otherwise?
    Nothing extra — `proxy(4)` is informational at the acceptor. It marks a service ticket the ticket-granting service issued from a `proxiable(3)` ticket, typically with different `caddr` values, so an application service that cares can notice it is not talking to the original client's host and refuse.
  • Why is forwarding usually requested at the very first exchange rather than later?
    The client must already hold a `forwardable(1)` ticket-granting ticket before the ticket-granting service will forward anything, and that bit is granted when the ticket-granting ticket is first issued in the `AS-REP`. If the initial ticket was not marked forwardable, no later `TGS-REQ` can add the bit.

A proxiable ticket is like handing a courier one prepaid label already addressed to a single depot. A forwarded ticket-granting ticket is handing over the franking machine: they can now post anything, anywhere, in your name.

saying these in an interview costs you the question

  • Says forwardable and proxiable are the same flag under two names.
  • Thinks a service can read the contents of a forwarded ticket-granting ticket.
  • Believes a proxy ticket lets the holder reach any service it likes.
  • Claims the flags are set by the application service rather than requested at the KDC.
  • Assumes a forwarded ticket-granting ticket is sealed under the holder's own key.
  • Thinks forwardable can be added to a ticket-granting ticket after it was issued.
open as a page

When a client sets GSS_C_DELEG_FLAG on a Kerberos context, what does the accepting service end up holding?

level: seniorimportance: should knowfreq 37%

basics

~20 s

A forwarded ticket-granting ticket for the client, plus its session key. GSS_C_DELEG_FLAG makes the initiator pack that credential into the AP-REQ Authenticator's checksum, so the acceptor can afterwards obtain service tickets in the client's name.

open as a page

In Kerberos, how does a service that authenticated a user without Kerberos obtain a service ticket in that user's name?

level: seniorimportance: should knowfreq 42%

basics

~20 s

Through the S4U2Self extension: the service presents its own ticket-granting ticket and asks the ticket-granting service for a service ticket to itself in the named user's name, with no proof from the user. S4U2Proxy then chains onward.

open as a page

Which Kerberos delegation model would you standardise on across many middle-tier services, and why does who holds the configuration decide it?

level: principalimportance: should knowfreq 29%

basics

~20 s

Resource-based delegation, in most estates: the target service declares who may impersonate to it, so the party bearing the loss holds the setting and a new service starts reachable by nobody. Constrained delegation puts that list on the middle tier instead.

open as a page