By my understanding, key derivation is when you take some data, say a password, and use a function to convert it into a number that can be used as a secret key in say elliptic curve cryptography.
Yes, this is correct, however, keep in mind that your password should have good enough strength to protect from brute-forcing. A common way is using the dicewire or Bip39 like password mechanisms, see in xkc936.
Once you derive the key $k$, then this is your private key, and $[k]G$ is your public key in ECC with the base point $G$ of the curve. Erase the $k$ after using, even don't store it in the memory, and keep your password safe!
Argon2 uses a random salt when hashing, which necessitates that the hash be different every time despite the same password being used.
Yes, that is correct, too. You may consider this like that with all of the parameters of the Argon2, you run a deterministic function. The same input will result from the same output. This is what we want from the hash functions, password hash functions, and Random Oracles; be deterministic; the same input must result in the same output.
Using different salt is used for deriving more than one key from a password. The salt at the same time is a good countermeasure aginst the rainbow tables where applicable.
If the hash is different, how can it be used to represent the same secret key?
To get the same key, you need to use the same parameters; the same password, the same salt, the same iteration, the same memory usage, and the same parallelization. Parameters apart from your password must not necessarily be secret, they can be stored openly. For example, this kind of information is stored in LUKS header, the important part is to keep your password secret all the time.
One must store these parameters when deriving the key from the password.
How is Argon2 used for key derivation?
First, decide your target security; i.e. how much do you want the life of the attacker is hard. Adjust the number of iterations, degree of parallelization, and memory usage according to your target security. Once you have decided, generate a uniform random salt. Determine the desired key size, like 256 bits (or 32 bytes). Now you are ready to use Argon2 with this information.
You supply your information to Argon and decide your target security;
Usage: ./argon2 [-h] salt [-i|-d|-id] [-t iterations] [-m memory] [-p parallelism] [-l hash length] [-e|-r] [-v (10|13)]
Password is read from stdin
Parameters:
salt The salt to use, at least 8 characters
-i Use Argon2i (this is the default)
-d Use Argon2d instead of Argon2i
-id Use Argon2id instead of Argon2i
-t N Sets the number of iterations to N (default = 3)
-m N Sets the memory usage of 2^N KiB (default 12)
-p N Sets parallelism to N threads (default 1)
-l N Sets hash output length to N bytes (default 32)
-e Output only encoded hash
-r Output only the raw bytes of the hash
-v (10|13) Argon2 version (defaults to the most recent version, currently 13)
-h Print argon2 usage
Note that the Argon2 has three types;
Argon2d is faster and uses data-depending memory access. Data dependency immediately enables side-channel. This is suitable for cryptocurrencies and applications with no threats from side-channel attacks.
Argon2i uses data-independent memory access and this is preferred for password hashing and password-based key derivations.
Argon2id In the first half of the first iteration works as Argon2i and for the rest works as the Argon2d. This enables both side-channel protection and time-memory trade-off.
and form draft-irtf-cfrg-argon2-03;
If you do not know the difference between them or you consider side-channel attacks as viable threat, choose Argon2id.