Skip to content
Français
Account: not signed in, sync available My learning
Select theme
Français

Define an entry point security policy

By updated

Improve this page

An entry point security policy is the written list of what you allow, what you refuse, and what you refuse without being asked. The entry point is the service that receives client requests, most often a reverse proxy (a server placed in front of your applications that receives requests on their behalf). This lesson teaches you to decide before writing a single directive: who may call which route, at what rate, whom you trust, and what must never reach the disk. It is aimed at a beginner who has already published a service and wants to protect it.

The lesson teaches the policy, not the syntax of a product. That syntax lives in the tool guides: Protecting the Traefik entry point, Protecting and observing Nginx and Protecting and observing HAProxy. Those pages say how to write a rule; this one says which rule to write, and how to check that it holds.

What you will learn

  • Write a policy per route, with a default deny, before choosing a directive.
  • Tell authentication, authorization, filtering and rate limiting apart.
  • Decide from which addresses an identity header is believed.
  • Close direct access to the application, which bypasses everything else.
  • Choose what the log erases, without making it silent.
  • Verify a policy through the status and body of responses.

Prerequisites

This lesson assumes you know how to publish a service behind an entry point and how to read an HTTP exchange. It does not re-explain these skills.

Why write a policy before a configuration?

A configuration says what the tool does; a policy says what you want it to do, and the second must exist before the first. A security directive can be present and protect nothing: it may target a prefix that matches no route, or protect one door while another is left open. Writing the policy first gives you a reference against which to judge the configuration.

A policy comes down to five questions, asked route by route. Who may call this route? Whom do we trust to say so? Where from can one arrive? At what rate? What do we keep of the exchange? The rest of the lesson answers each one. A backend is the application the entry point calls behind it; it must not be reached directly by an external client.

QuestionDecision to write
Who may?An identity required per route, deny by default
Whom do we trust?The list of addresses that may set an identity
Where from?A single path, the one through the entry point
At what rate?A ceiling of requests per caller
What do we keep?Secret headers erased from the log

Who may call which route?

The right to call a route is decided route by route, with an identity required for each one and a refusal for everything else. Take a service that publishes three routes: / is public, /compte is reserved for a logged-in user, /admin for administration. Three routes, three different requirements, and a fourth decision that is often forgotten: what does the entry point answer for a route nobody planned?

Two words not to confuse. Authentication answers "who are you?": it verifies an identity, for example a token presented in the Authorization header. Authorization answers "are you allowed to do this?": an authenticated user does not automatically have access to administration. HTTP status codes follow this distinction, with a nuance that RFC 9110 takes care to set out. 401 means the request does not carry valid credentials: they are missing, but also expired or wrong, and the response must then carry a WWW-Authenticate header that says how to authenticate. 403 means the server understood the request and refuses to fulfill it: most often because the identity is recognized without sufficient rights, but a refusal can also have nothing to do with identity, for example an unauthorized source address.

RouteAnonymousUserAdministrator
/allowedallowedallowed
/compterefused (401)allowedallowed
/adminrefused (401)refused (403)allowed

This table is the policy, before any tool. Read it as a contract: it also fixes what must keep working. A policy that refuses everyone satisfies every refusal and removes the service; that is an outage, not a protection. The least privilege principle applies here: each identity receives the strict minimum, nothing more.

What remains is the default deny. A route the policy does not name must be refused, not opened. In the opposite direction, the forgotten rule is a hole: the day someone publishes /export, nothing stops it. For administration routes, a filter on the source address is often added (accept only the team's networks), which complements authentication without replacing it. A caller refused for their address receives a 403 even if anonymous, since that refusal does not depend on their identity; the table above assumes an authorized address.

Whom do you trust to say who is calling?

An identity header is believed only if it is set by a proxy whose address you wrote in the policy. Many architectures offload authentication to an upstream component, which passes the result to the application in a header, for example X-Identite: admin. The problem is that a header is text: any client can write it.

If the application believes every X-Identite header, an anonymous caller sends X-Identite: admin and becomes administrator without a token. This is a forged header. The remedy is a list of trusted proxies: the addresses whose header is accepted. A header coming from any other address is ignored or rejected, as if it were absent.

The same reasoning applies to the client address. A proxy placed behind another one only sees the address of the one before it; the original address travels in the X-Forwarded-For header, which the client can also forge. This header is therefore read only from explicitly listed proxies. Even when it comes from a trusted proxy, only the address that this proxy added is reliable: the chain that precedes it is not (RFC 7239, section 8.1). The page Protecting the Traefik entry point applies the same caution to ipAllowList behind an upstream proxy.

A private network is not universal proof of trust. An internal address says where the caller is, not who they are or what they have done with their machine. List precise addresses, never "the whole internal network" out of laziness.

How do you prevent the entry point from being bypassed?

A policy placed in front of a door that can be bypassed protects nothing, so you must close direct access to the application. It is a common and silent bypass: the entry point filters, but the application also listens on its own port, reachable from the clients' network. A caller who knows that port ignores the entry point and its rules.

Two actions close this door, and both are valid. The first is to bind the application to the loopback interface: it then listens only on 127.0.0.1, an address that only answers to the machine itself, so only a proxy on the same machine reaches it. The second is to refuse the port from outside with a firewall rule. The first has the advantage of depending on no rule that could be erased by mistake: as long as the kernel keeps its default setting (route_localnet at 0), an application bound to 127.0.0.1 is reachable only from the host. This is a cautionary note, not an absolute rule: some container configurations enable route_localnet, and the firewall then becomes indispensable.

Always verify from another machine. A test run on the machine itself goes through the loopback interface and succeeds even when the port is open to the network; the lesson Linking interfaces, ports, firewall and exposure explains why. The forged header bypass from the previous section is the second path of the same family: you avoid the rule instead of crossing it.

What request rate should you tolerate?

Rate limiting caps the number of requests a caller can send over a period, to slow abuse without hindering normal use. It addresses two risks: repeated password attempts (credential stuffing, detailed in Attacks on credentials and the network (in French)) and the exhaustion of an application by an overzealous caller.

Three decisions are made. The threshold: too low, it blocks normal users; too high, it protects almost nothing. Set it from the observed legitimate traffic, not by guesswork. The key: the ceiling is counted per address, per token or per route, but never by a value the client chooses itself, because it would change it on every request and reset the counter to zero. The sensitive routes: a login route deserves a much tighter ceiling than the home page.

A limit is not the same as protection against denial of service (an attack that overwhelms a service to make it unavailable). A ceiling set on a single server slows an overly active client; it does not save a network link saturated by thousands of sources. There are also limits of shape: maximum request size, maximum duration of an exchange, slow connections that monopolize resources. The policy names them, the tool pages give the directives. The lab for this lesson does not measure throughput: it focuses on access, trust and logs.

What should you write in logs, and what should you never write?

A log must keep enough to understand an incident, and never enough to replay a session. The entry point sees credentials go by: the Authorization header carries a token or a password, the Cookie header carries a session. If the log copies them, these secrets stay readable on disk as long as the log lives, and as long as its backups do.

The policy therefore lists the headers to erase before writing: they are replaced with a marker (for example [efface]) instead of being copied. Everything else is kept: date, route, status, source address. Apply the same vigilance to any derived file, such as a summary or an export: a secret copied into a summary is still a secret in clear text.

The opposite excess is also a fault. An empty log protects all the secrets and helps nobody the day an intrusion must be understood. Erasing is not the same as logging nothing. The same logic applies to the security headers of the response (HSTS, content policy): they protect the client's browser, they are tuned to the application, and a setting that is too strict breaks legitimate resources. Their detail is in the tool pages.

How do you prove that the policy holds?

A policy is proven by what the service answers to real requests, never by what the configuration file declares. A file can name a rule that the tool applies to nothing: a badly written prefix, a path that matches no route. The only proof is to send the request, from an independent machine, and read the response.

Read two things, not one: the status and the body. A 403 whose body contains the administration page has refused in form only and still leaks. Conversely, a 200 that returns the public page on /admin is not a leak, whereas a 200 that returns the administration content is one. The status alone does not tell them apart. So find, in each page, a sentence of its own (a marker) and look for it in the body.

A complete proof combines four checks:

  1. The legitimate request passes. Each authorized identity gets its content. This is the anchor: refusing everyone would satisfy the other checks by removing the service.
  2. Sensitive routes refuse, and the body of the refusal does not carry the protected content.
  3. No bypass succeeds: neither direct access to the application, nor the forged identity header.
  4. No planted secret survives. You send a sentinel value (a unique, randomly drawn string) in Cookie and Authorization, then search for it in the log. You also check that the log is not empty.

The two halves of a check count together. "The service works" is true before any policy; "the refusals work" is true if everything is closed. Only their conjunction proves anything.

Practice

The lab publishes three routes, /, /compte and /admin, served by a configurable guard that applies a policy file to the letter, empty at the start: everything passes, every identity header is believed, the log keeps everything. You write the policy with three keys: the identities required per route prefix, the proxys_de_confiance and the headers to erase under journal.effacer. You also close direct access to the application's port. The validation sends real requests from an independent client, reads status and body, and searches for a sentinel value in the log and the directory. It measures neither rate limiting nor response headers.

Key points

These points summarize the policy decisions, whatever the tool.

  • A policy is written route by route, with an identity required and a default deny.
  • 401 says "no valid credentials" (the response then carries WWW-Authenticate), 403 says "understood, but refused": most often a recognized identity without sufficient rights, sometimes a refusal unrelated to identity, such as an unauthorized source address. Authentication and authorization are two questions.
  • An identity header is believed only from a listed trusted proxy; otherwise it can be forged.
  • Closing direct access (loopback interface or firewall) is indispensable: without it, the policy can be bypassed.
  • A rate ceiling is tuned on legitimate traffic and does not replace the defense against a volumetric denial of service.
  • The log erases secrets without going silent.
  • You prove by the status and body of real requests, with the legitimate request and the refusal together.

Knowledge check

The quiz checks the policy decisions and the way to prove they hold.

Knowledge check

Check what you have learned with this interactive quiz

8 questions
8 min
70% to pass

How it works

  • The timer starts when you click Start
  • Multiple choice, true/false and short answer questions
  • You can move between questions
  • Detailed results are shown at the end

Starts the quiz and the timer

Is this project useful to you?

The guides, courses, quizzes and labs stay free. If you use them regularly, you can contribute to their upkeep and development.

Become a supporting member (new tab) One-time support (new tab) Learn more

Follow the project on LinkedIn