Most Oracle security conversations start at the database level. Roles, profiles, privilege grants, auditing. All of that assumes the user has already proven who they are. Kerberos integration with Active Directory starts three layers above that, at the network authentication layer, and the configuration touches the operating system, the Oracle Net stack, the Windows client, and Active Directory at once. Four moving parts, four owners, and in most organizations at least two of those owners do not report to the same director.

That is why this deserves more than a brief how-to. The configuration is well documented and not especially hard. The problem is that when the trust chain breaks, the error is almost never about the thing that is broken. A realm typo surfaces as a network failure. Clock drift surfaces as an expired ticket. A keytab with the wrong crypto flags validates on the client and fails at the listener. You debug the wrong layer, with the wrong team, for most of a day.

What has to align for this to work

The trust chain requires four things to match exactly. The realm name in krb5.conf on the Linux server, the realm name in krb5.ini on the Windows client, the service principal name baked into the keytab, and the listener hostname as DNS actually resolves it. Not as you believe DNS resolves it. As it resolves, from the client, at the moment of connection.

A mismatch in any of the four breaks authentication, including a case difference in the realm name. Kerberos realms are conventionally uppercase and the convention is load bearing. CORP.EXAMPLE.COM and corp.example.com are different realms, and the failure looks like the client could not reach the KDC rather than asked for the wrong one.

On the database server, sqlnet.ora carries the Kerberos configuration. Note SQLNET.KERBEROS5_CONF_MIT = TRUE, which tells Oracle to parse the config in MIT format. Leave it off and Oracle expects the older Oracle-specific format and misreads a file that looks correct.

SQLNET.AUTHENTICATION_SERVICES = (BEQ,KERBEROS5)
SQLNET.FALLBACK_AUTHENTICATION = TRUE
SQLNET.KERBEROS5_CONF = $ORACLE_HOME/network/admin/krb5.conf
SQLNET.KERBEROS5_CONF_MIT = TRUE
SQLNET.KERBEROS5_CLOCKSKEW = 6000
SQLNET.KERBEROS5_CC_NAME = /tmp/krb5cc_500
SQLNET.KERBEROS5_KEYTAB = $ORACLE_HOME/network/admin/oracle.keytab
SQLNET.AUTHENTICATION_KERBEROS5_SERVICE = oracle

SQLNET.FALLBACK_AUTHENTICATION deserves a note. Setting it to TRUE allows Oracle to fall back to native database authentication if Kerberos authentication fails. During initial setup this is useful, because it means a misconfigured Kerberos environment does not lock you out of the database entirely. Once the configuration is stable and tested, evaluate whether fallback should be disabled for security-sensitive environments where you want to enforce Kerberos as the only authentication path.

The krb5.conf on the Linux server ties the realm to the domain controller and maps DNS domains back to it:

[libdefaults]
  default_realm = CORP.EXAMPLE.COM
  dns_lookup_realm = false
  dns_lookup_kdc = false
  forwardable = true
  ticket_lifetime = 24h

[realms]
  CORP.EXAMPLE.COM = {
    kdc = dc01.corp.example.com:88
    admin_server = dc01.corp.example.com:749
    default_domain = corp.example.com
  }

[domain_realm]
  .corp.example.com = CORP.EXAMPLE.COM
  corp.example.com = CORP.EXAMPLE.COM

The [domain_realm] section is the one people leave out. Without it, the client resolves the listener hostname and has no idea which realm that host belongs to, so it never asks for the right ticket.

The Windows client needs its own sqlnet.ora. It is shorter, and MSLSA: is the entry that matters: it points Oracle at the Windows LSA credential cache, where the ticket from domain login already lives. Point it elsewhere and you force users to run kinit by hand for a ticket Windows already handed them.

SQLNET.AUTHENTICATION_SERVICES = (KERBEROS5)
SQLNET.KERBEROS5_CONF = C:\ProgramData\MIT\Kerberos5\krb5.ini
SQLNET.KERBEROS5_CONF_MIT = TRUE
SQLNET.KERBEROS5_CC_NAME = MSLSA:
SQLNET.AUTHENTICATION_KERBEROS5_SERVICE = oracle

The three failure modes that cost the most time

First, clock skew. Kerberos is time sensitive by design, because ticket freshness is what stops replay. If the database server and the domain controller disagree by more than the clockskew value, authentication fails and the error talks about ticket validity rather than clocks. The default tolerance is 300 seconds. The config above sets 6000 to buy room, but that is a tuning knob, not a fix. Check NTP synchronization on the Linux server against the domain controller before anything else. A suspended and resumed virtual machine is the usual culprit, and it will drift again.

Second, the keytab generation command. The ktpass command on Windows needs -crypto ALL and -ptype KRB5_NT_PRINCIPAL. A narrower crypto set or the wrong principal type produces a keytab that validates locally with klist and fails at the Oracle listener. This one is expensive because the local validation passing sends you looking at Oracle Net, when the fix lives with the AD administrator. Retrying with the existing keytab will never work, and that takes a while to argue when klist keeps saying the file is fine.

Third, os_authent_prefix. Oracle prepends a string to the operating system username when it maps external authentication, and the default is OPS$. If the database account was not created with that prefix, or the parameter was not cleared first, authentication succeeds at the Kerberos layer and fails at the Oracle layer. The user proved who they were and Oracle still does not know who that is. Set it empty:

ALTER SYSTEM SET os_authent_prefix='' SCOPE=spfile;

That is SCOPE=spfile, so it takes a database restart to apply. Plan the outage, and create the externally identified users after the restart, not before. The prefix binds at creation time.

Validating each layer before you connect

Do not go straight to sqlplus. Validate one layer at a time, because each check isolates a different owner.

On the Linux server, confirm the keytab is valid and obtains a ticket:

oklist -k -t $ORACLE_HOME/network/admin/oracle.keytab
okinit -k oracle/db01.corp.example.com@CORP.EXAMPLE.COM
oklist

On the Windows client, confirm the AD ticket is present:

kinit user@CORP.EXAMPLE.COM
klist

Then, and only then, connect:

sqlplus /@TNS_ALIAS

The scoping is the whole point. If the first two succeed and the sqlplus fails, the problem is not Kerberos and it is not Active Directory. It is Oracle Net configuration or the database user mapping, and you can stop pulling the AD team into the call. I have watched teams spend two days on a domain controller that was working the entire time, because nobody established which layer was broken before escalating.

Why it is worth it

This is a lot of setup for something users will never see. But for an organization already invested in Active Directory for identity, Kerberos authentication to Oracle removes password management from database accounts entirely. No password to rotate, no shared credential in a connection string, no separate offboarding step when someone leaves. Access is auditable at the AD level and the Oracle level at once, from the same identity. You stand it up once, painfully, and it keeps paying every quarter you do not spend rotating credentials or reconciling two directories that disagree about who works here.