I know they have to be random
Well, kind of. More precisely, they have to be indistinguishable from random.
The goal when choosing a key is that the adversary (the “bad guy”) won't be able to find the key. Since the adversary may know how our system works (Kerckhoffs's principle), we need to find a way to generate keys that don't only depend on a deterministic computation (which the adversary could reproduce). Therefore all keys must depend on something that the adversary does not know. Such a thing is called a “true” random value.
Random values can be generated using various unpredictable physical processes. A device that implements such a process is called a hardware or “true” random number generator (HRNG or TRNG). Pretty much all modern smartphones and PC, and a growing number of embedded devices, include a HRNG.
Once a system has been “seeded” with a true random value, it can use a deterministic calculation called cryptographically secure pseudorandom generator (CSPRNG) (pseudorandom generator for short) to generate a practically infinite stream of random values. These values are random in the sense that an adversary with finite computing power cannot distinguish them from “true” random values. In a cryptographic context, a random generator (RNG) is a CSPRNG seeded by a HRNG.
is that all the properties required?
Each key must be indistinguishable from random, from the point of view of potential adversaries. This can mean that the key is generated randomly (as explained above). But not all keys are generated randomly: some keys are calculated deterministically from a mixture of keys and other inputs. Such processes are called key derivation. HKDF is an example of a key derivation function. A pseudorandom function (PRF) can be a building block for a KDF. For example, when two computers communicate over an encrypted channel, they typically derive the same keys from a shared secret.
“Random”, for a key, means as close as possible to uniformly random among the set of possible keys. What this means depends on the type of key.
Generally, symmetric encryption uses keys that are just an array of bytes, and so generating an $n$-bit key just means generating $n$ random bits and calling that a key. This is true, for example, of block ciphers such as AES and Camellia, of stream ciphers such as Chacha20, of MAC algorithms such as HMAC and Poly1305, etc.
Classical asymmetric encryption uses keys that are numbers with certain properties, and so generating such keys can involve additional calculations. A generic way of generating a key that can be represented by an $n$-bit string is to generate $n$ random bits, check if this represents a valid key, and if not try again. (This assumes that the representation is unique, i.e. that there aren't two identical keys with the same representation.) This approach works well for typical ECC keys, where a private key is a number between $1$ and $2^n - a$ with $a \ll 2^n$, so it works well to generate a random $n$-bit string and interpret it as a number between $0$ and $2^n-1$ and try again if you hit one of the few invalid values. Some other cryptosystems, such as RSA, involve far more complex key generation processes, but even so it uses “generate a random bit-string” and “try again if the value is unsuitable” as building blocks.
Uniform random
. Alas, too broad and does not have a simple answer; What issues are there while using Linux's /dev/urandom for generating cryptographic keys?. I suggest you search our site and concentrate one at a time. $\endgroup$