NixOS doesn't actually use callPackage. it uses lib.evalModules. The fact there is a difference between how NixOS is evaluated, vs how Nixpkgs is evaluated is something I actually find quite annoying. Whilst nixpkgs is all about functions and dependency injection, NixOS is all about merging dictionaries.
Here is some context, with corresponding criticsm by the person behind Guix, which might give some interesting insights
https://discourse.nixos.org/t/best-resources-for-learning-ab...
To answer your question, { config, pkgs, ... }: declares a function that takes an attribute set containing values for "config" and "pkgs". The ellipsis indicates that it's okay to pass extra attributes.
Nixos-rebuild calls your function by: with (import <nixpkgs> {}); callPackage ./configuration.nix {}
<nixpkgs> is a file containing the set of all symbols (packages are under pkgs, Nix config lives in config, etc.) like a root namespace. callPackage inherits all those symbols and passes them to the function, which is how they got bound.
0. https://nixos.org/nixos/nix-pills/index.html
1. https://learnxinyminutes.com/docs/nix/
EDIT: I guess it's also like Git where it's really confusing until a moment of enlightenment where it all makes sense.