Basically, the choice depends mainly on two criteria: whether the data to store is big or small, and whether it is rewritten often or not:
- EEPROM is great for small data that changes often. The reason is: it is sold only for small sizes, but they can usually be single-byte erased. Moreover, EEPROM endurance is very high (millions of cycles).
- Flash is great for big data that doesn't change often. It is available cheaply for big sizes, but when you need to overwrite data, you can do it only for a whole page, which can be a few kB. And the endurance is more in the range of 100.000 cycles.
I won't go into more details on the difference between both, it has already been covered:
Regarding SD cards: SD card is a removable type of flash, and as such, it follows the same constraints as a regular flash. However, it typically uses NAND flash whereas usually, serial flash chips use NOR flash. NAND flash is more convenient for writing (smaller pages, faster erase) but is less reliable. You may get bad blocks after a while, if you do a lot of writes. Wear leveling can mitigate this, but it is not always implemented in cheap SD cards (Is it true that a SD/MMC Card does wear levelling with its own controller?). You could implement it in software, but it is not trivial.
The choice of the interface (I2C or SPI) is completely unrelated, however. I2C is slower but uses fewer pins. I2C EEPROM is also usually cheaper than SPI, but you usually decide to use one or the other depending on the way you attributed MCU pins in your application.
Now, you have given specific use cases, so let's look at them one by one:
System configuration and calibration data
Well, this one does not put many constraints: this data is usually very small and does not change often. So, here, the simplest is to put it where it costs less:
- either the internal MCU EEPROM if you have one
- or some external flash if you already need it for some other purposes
- or eventually a SD card if you have no other persistent storage available. Note however that, because SD card can be eventually removed and put in another device, calibration data wouldn't be consistent anymore. So you may want to avoid that.
If there are no other needs for persistent storage in your device and there is no internal EEPROM in the MCU, you could eventually use a specific flash page in the flash of the MCU itself (if the MCU allows this). Otherwise, you can fall back on a small external EEPROM.
Note that in the specific case of MAC addresses, there are EEPROMs that are sold with a pre-programmed MAC address inside, guaranteed to be unique (e.g. Microchip 24AAxxx). So that would be the way to go, unless you have been officially attributed an address block by IEEE or are willing to risk using locally attributed addresses.
This is usually big, and changes often. Big means flash, not EEPROM. So you can go either with a flash chip or an SD card, but if the logs are really rewritten often, you'd better use a SD card. Otherwise, you risk wearing out the flash chip, and if it is soldered on the board, it will be more difficult to replace than a SD card. Also note that, when writing logs by cycling over the whole flash pages, wear leveling then actually becomes trivial to implement.
In case these are small logs, you're lucky, go with EEPROM (as long as the endurance is acceptable).
Note that, if endurance is a real problem, there are additional solutions with practically unlimited endurance and relatively big size: F-RAM and MRAM. But these cost an arm and a leg, and you didn't mention them as an option. Also note that these two newer technologies achieve much better erase/write speed than flash, so for continuous logging, this may be interesting.
Code and code resources
Usually big, but does not change often. Obviously, if your MCU has an internal flash (like most do), that would be the way to go: it is there for this very purpose. If it doesn't, or if it is too small, an external flash chip (typically NOR flash) is ideal for this. NOR flash is more appropriate than NAND because you want high integrity for the code, and NAND flash are usually more difficult to interface directly with MCUs/SoCs. Note that, for executing code directly from an external flash, the MCU needs to have an address space that goes to this external flash, and most low-end MCUs are not able to do this (this functionality is typically is called XIP: eXecute-In-Place).
Security and digital rights management
This one is trickier. If it really contains sensitive data that should never be extracted, you'd better actually use a smart card in SIM form factor (eventually with some custom firmware in it). But this of course complicates the design a lot. An alternative (easier and cheaper) solution may be a dedicated security chip like the Atmel AT88SC series, but the commands available on the chip have to make sense for your specific application. What can be done on this chip and under which condition has to be carefully planned.
If you need just "basic" security, the easiest is to use the internal MCU EEPROM. It won't be as secure as a smart card or dedicated chip (which contains specific security measures, like protection against light attacks, countermeasures against power/fault analysis within the chip, etc...), but this is the best you can do.
Otherwise, if there is no internal EEPROM, you'll end up with the same options as for the configuration/calibration data. However, using any external chip to store secure data is a risk since the data lines could be easily monitored with a simple logic analyser, and the sensitive data extracted. So, even if EEPROM is said to be more difficult to tamper with than flash, choosing one or the other in the case of an external chip doesn't make any difference from a security point of view.
Finally, the SD card is definitely the worst idea here, as it is removable. The sensitive data could then be read from a PC, without even needing any specific hardware.